[Patch 0/6] MIPS Hardware watchpoint support for gdb (version 2). - Kernel

This is a discussion on [Patch 0/6] MIPS Hardware watchpoint support for gdb (version 2). - Kernel ; This is my second take at MIPS watch register support. Changes from the previous version include: * Change layout of structures used by ptrace to eliminate holes. * Use [set|clear]_tsk_thread_flag() and friends instead of racy direct access. * mips64 support ...

+ Reply to Thread
Results 1 to 7 of 7

Thread: [Patch 0/6] MIPS Hardware watchpoint support for gdb (version 2).

  1. [Patch 0/6] MIPS Hardware watchpoint support for gdb (version 2).

    This is my second take at MIPS watch register support.

    Changes from the previous version include:

    * Change layout of structures used by ptrace to eliminate holes.

    * Use [set|clear]_tsk_thread_flag() and friends instead of racy direct
    access.

    * mips64 support (untested).

    * Fix sparse warnings.

    For this version of the patch you will need the corresponding gdb patch
    which can be found here:

    http://sourceware.org/ml/gdb-patches.../msg00642.html

    David Daney
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  2. [PATCH 1/6] Add HARDWARE_WATCHPOINTS configure option.

    Add HARDWARE_WATCHPOINTS configure option.

    This is automatically set for all MIPS32 and MIPS64 processors.

    Signed-off-by: David Daney
    ---
    arch/mips/Kconfig | 7 +++++++
    1 files changed, 7 insertions(+), 0 deletions(-)

    diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
    index 8724ed3..a52d3a8 100644
    --- a/arch/mips/Kconfig
    +++ b/arch/mips/Kconfig
    @@ -1344,6 +1344,13 @@ config CPU_SUPPORTS_32BIT_KERNEL
    config CPU_SUPPORTS_64BIT_KERNEL
    bool

    +#
    +# Set to y for ptrace access to watch registers.
    +#
    +config HARDWARE_WATCHPOINTS
    + bool
    + default y if CPU_MIPS32 || CPU_MIPS64
    +
    menu "Kernel type"

    choice
    --
    1.5.5

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  3. [PATCH 3/6] Probe watch registers and report configuration.

    Probe watch registers and report configuration.

    Probe for watch register characteristics, and report them in /proc/cpuinfo.

    Signed-off-by: David Daney
    ---
    arch/mips/kernel/cpu-probe.c | 4 ++++
    arch/mips/kernel/proc.c | 10 ++++++++++
    2 files changed, 14 insertions(+), 0 deletions(-)

    diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
    index 89c3304..1563049 100644
    --- a/arch/mips/kernel/cpu-probe.c
    +++ b/arch/mips/kernel/cpu-probe.c
    @@ -21,6 +21,7 @@
    #include
    #include
    #include
    +#include

    /*
    * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
    @@ -678,6 +679,9 @@ static void __cpuinit decode_configs(struct cpuinfo_mips *c)
    static inline void cpu_probe_mips(struct cpuinfo_mips *c)
    {
    decode_configs(c);
    +#if defined(CONFIG_HARDWARE_WATCHPOINTS)
    + mips_probe_watch_registers(c);
    +#endif
    switch (c->processor_id & 0xff00) {
    case PRID_IMP_4KC:
    c->cputype = CPU_4KC;
    diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
    index 36f0653..e2f716c 100644
    --- a/arch/mips/kernel/proc.c
    +++ b/arch/mips/kernel/proc.c
    @@ -50,8 +50,18 @@ static int show_cpuinfo(struct seq_file *m, void *v)
    seq_printf(m, "tlb_entries\t\t: %d\n", cpu_data[n].tlbsize);
    seq_printf(m, "extra interrupt vector\t: %s\n",
    cpu_has_divec ? "yes" : "no");
    +#ifdef CONFIG_HARDWARE_WATCHPOINTS
    + seq_printf(m, "hardware watchpoint\t: %s",
    + cpu_has_watch ? "yes" : "no\n");
    + if (cpu_has_watch)
    + seq_printf(m, ", count: %d, address mask: 0x%04x, irw mask 0x%02x\n",
    + cpu_data[n].watch_reg_count,
    + cpu_data[n].watch_reg_mask,
    + cpu_data[n].watch_reg_irw);
    +#else
    seq_printf(m, "hardware watchpoint\t: %s\n",
    cpu_has_watch ? "yes" : "no");
    +#endif
    seq_printf(m, "ASEs implemented\t:%s%s%s%s%s%s\n",
    cpu_has_mips16 ? " mips16" : "",
    cpu_has_mdmx ? " mdmx" : "",
    --
    1.5.5

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  4. [PATCH 2/6] Add HARDWARE_WATCHPOINTS definitions and support code.

    Add HARDWARE_WATCHPOINTS definitions and support code.

    Signed-off-by: David Daney
    ---
    arch/mips/kernel/Makefile | 1 +
    arch/mips/kernel/watch.c | 158 ++++++++++++++++++++++++++++++++++++++++
    include/asm-mips/cpu-info.h | 5 +
    include/asm-mips/processor.h | 32 ++++++++
    include/asm-mips/thread_info.h | 2 +
    include/asm-mips/watch.h | 32 ++++++++
    6 files changed, 230 insertions(+), 0 deletions(-)
    create mode 100644 arch/mips/kernel/watch.c
    create mode 100644 include/asm-mips/watch.h

    diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
    index ed3d160..fdd59cd 100644
    --- a/arch/mips/kernel/Makefile
    +++ b/arch/mips/kernel/Makefile
    @@ -72,6 +72,7 @@ obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o

    obj-$(CONFIG_KGDB) += gdb-low.o gdb-stub.o
    obj-$(CONFIG_PROC_FS) += proc.o
    +obj-$(CONFIG_HARDWARE_WATCHPOINTS) += watch.o

    obj-$(CONFIG_64BIT) += cpu-bugs64.o

    diff --git a/arch/mips/kernel/watch.c b/arch/mips/kernel/watch.c
    new file mode 100644
    index 0000000..9eb7c4f
    --- /dev/null
    +++ b/arch/mips/kernel/watch.c
    @@ -0,0 +1,158 @@
    +/*
    + * This file is subject to the terms and conditions of the GNU General Public
    + * License. See the file "COPYING" in the main directory of this archive
    + * for more details.
    + *
    + * Copyright (C) 2008 David Daney
    + */
    +
    +#include
    +
    +#include
    +
    +void mips_install_watch_registers(void)
    +{
    + struct mips3264_watch_reg_state *watches =
    + &current->thread.watch.mips3264;
    + switch (current_cpu_data.watch_reg_count) {
    + default:
    + BUG();
    + case 8:
    + write_c0_watchlo7(watches->watchlo[7]);
    + /* Write 1 to the I, R, and W bits to clear them. */
    + write_c0_watchhi7(watches->watchhi[7] | 7);
    + case 7:
    + write_c0_watchlo6(watches->watchlo[6]);
    + write_c0_watchhi6(watches->watchhi[6] | 7);
    + case 6:
    + write_c0_watchlo5(watches->watchlo[5]);
    + write_c0_watchhi5(watches->watchhi[5] | 7);
    + case 5:
    + write_c0_watchlo4(watches->watchlo[4]);
    + write_c0_watchhi4(watches->watchhi[4] | 7);
    + case 4:
    + write_c0_watchlo3(watches->watchlo[3]);
    + write_c0_watchhi3(watches->watchhi[3] | 7);
    + case 3:
    + write_c0_watchlo2(watches->watchlo[2]);
    + write_c0_watchhi2(watches->watchhi[2] | 7);
    + case 2:
    + write_c0_watchlo1(watches->watchlo[1]);
    + write_c0_watchhi1(watches->watchhi[1] | 7);
    + case 1:
    + write_c0_watchlo0(watches->watchlo[0]);
    + write_c0_watchhi0(watches->watchhi[0] | 7);
    + }
    +}
    +
    +/*
    + * Read back the watchhi registers so the user space debugger has
    + * access to the I, R, and W bits.
    + */
    +void mips_read_watch_registers(void)
    +{
    + struct mips3264_watch_reg_state *watches =
    + &current->thread.watch.mips3264;
    + switch (current_cpu_data.watch_reg_count) {
    + default:
    + BUG();
    + case 8:
    + watches->watchhi[7] = read_c0_watchhi7();
    + case 7:
    + watches->watchhi[6] = read_c0_watchhi6();
    + case 6:
    + watches->watchhi[5] = read_c0_watchhi5();
    + case 5:
    + watches->watchhi[4] = read_c0_watchhi4();
    + case 4:
    + watches->watchhi[3] = read_c0_watchhi3();
    + case 3:
    + watches->watchhi[2] = read_c0_watchhi2();
    + case 2:
    + watches->watchhi[1] = read_c0_watchhi1();
    + case 1:
    + watches->watchhi[0] = read_c0_watchhi0();
    + }
    +}
    +
    +void mips_clear_watch_registers(void)
    +{
    + switch (current_cpu_data.watch_reg_count) {
    + default:
    + BUG();
    + case 8:
    + write_c0_watchlo7(0);
    + case 7:
    + write_c0_watchlo6(0);
    + case 6:
    + write_c0_watchlo5(0);
    + case 5:
    + write_c0_watchlo4(0);
    + case 4:
    + write_c0_watchlo3(0);
    + case 3:
    + write_c0_watchlo2(0);
    + case 2:
    + write_c0_watchlo1(0);
    + case 1:
    + write_c0_watchlo0(0);
    + }
    +}
    +
    +__init void mips_probe_watch_registers(struct cpuinfo_mips *c)
    +{
    + unsigned int t;
    +
    + if ((c->options & MIPS_CPU_WATCH) == 0)
    + return;
    + /*
    + * Check which of the I,R and W bits are supported, then
    + * disable the register.
    + */
    + write_c0_watchlo0(7);
    + t = read_c0_watchlo0();
    + write_c0_watchlo0(0);
    + c->watch_reg_irw = t & 7;
    +
    + /* Write the mask bits and read them back to determine which
    + * can be used. */
    + c->watch_reg_count = 1;
    + t = read_c0_watchhi0();
    + write_c0_watchhi0(t | 0xff8);
    + t = read_c0_watchhi0();
    + c->watch_reg_mask = t & 0xff8;
    + if ((t & 0x80000000) == 0)
    + return;
    +
    + c->watch_reg_count = 2;
    + t = read_c0_watchhi1();
    + if ((t & 0x80000000) == 0)
    + return;
    +
    + c->watch_reg_count = 3;
    + t = read_c0_watchhi2();
    + if ((t & 0x80000000) == 0)
    + return;
    +
    + c->watch_reg_count = 4;
    + t = read_c0_watchhi3();
    + if ((t & 0x80000000) == 0)
    + return;
    +
    + c->watch_reg_count = 5;
    + t = read_c0_watchhi4();
    + if ((t & 0x80000000) == 0)
    + return;
    +
    + c->watch_reg_count = 6;
    + t = read_c0_watchhi5();
    + if ((t & 0x80000000) == 0)
    + return;
    +
    + c->watch_reg_count = 7;
    + t = read_c0_watchhi6();
    + if ((t & 0x80000000) == 0)
    + return;
    +
    + c->watch_reg_count = 8;
    +}
    diff --git a/include/asm-mips/cpu-info.h b/include/asm-mips/cpu-info.h
    index 0c5a358..7d3a093 100644
    --- a/include/asm-mips/cpu-info.h
    +++ b/include/asm-mips/cpu-info.h
    @@ -49,6 +49,11 @@ struct cpuinfo_mips {
    unsigned int fpu_id;
    unsigned int cputype;
    int isa_level;
    +#if defined(CONFIG_HARDWARE_WATCHPOINTS)
    + unsigned int watch_reg_count;
    + unsigned int watch_reg_mask;
    + unsigned int watch_reg_irw;
    +#endif
    int tlbsize;
    struct cache_desc icache; /* Primary I-cache */
    struct cache_desc dcache; /* Primary D or combined I/D cache */
    diff --git a/include/asm-mips/processor.h b/include/asm-mips/processor.h
    index 58cbac5..0ae418a 100644
    --- a/include/asm-mips/processor.h
    +++ b/include/asm-mips/processor.h
    @@ -105,6 +105,29 @@ struct mips_dsp_state {
    {0,} \
    }

    +#ifdef CONFIG_HARDWARE_WATCHPOINTS
    +
    +#define NUM_WATCH_REGS 8
    +
    +struct mips3264_watch_reg_state {
    + /* The width of watchlo is 32 in a 32 bit kernel and 64 in a
    + 64 bit kernel. We use unsiged long as it has the same
    + property. */
    + unsigned long watchlo[NUM_WATCH_REGS];
    + /* The width of watchhi is always 32 bits. */
    + __u32 watchhi[NUM_WATCH_REGS]; };
    +
    +union mips_watch_reg_state {
    + struct mips3264_watch_reg_state mips3264;
    +};
    +
    +#define INIT_WATCH .watch = {{{0,},},}
    +
    +#define OPTIONAL_INIT_WATCH INIT_WATCH,
    +#else
    +#define OPTIONAL_INIT_WATCH
    +#endif
    +
    typedef struct {
    unsigned long seg;
    } mm_segment_t;
    @@ -137,6 +160,11 @@ struct thread_struct {
    /* Saved state of the DSP ASE, if available. */
    struct mips_dsp_state dsp;

    +#ifdef CONFIG_HARDWARE_WATCHPOINTS
    + /* Saved watch register state, if available. */
    + union mips_watch_reg_state watch;
    +#endif
    +
    /* Other stuff associated with the thread. */
    unsigned long cp0_badvaddr; /* Last user fault */
    unsigned long cp0_baduaddr; /* Last kernel fault accessing USEG */
    @@ -193,6 +221,10 @@ struct thread_struct {
    .dspcontrol = 0, \
    }, \
    /* \
    + * saved watch register stuff \
    + */ \
    + OPTIONAL_INIT_WATCH \
    + /* \
    * Other stuff associated with the process \
    */ \
    .cp0_badvaddr = 0, \
    diff --git a/include/asm-mips/thread_info.h b/include/asm-mips/thread_info.h
    index b2772df..e31de4b 100644
    --- a/include/asm-mips/thread_info.h
    +++ b/include/asm-mips/thread_info.h
    @@ -122,6 +122,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
    #define TIF_32BIT_REGS 22 /* also implies 16/32 fprs */
    #define TIF_32BIT_ADDR 23 /* 32-bit address space (o32/n32) */
    #define TIF_FPUBOUND 24 /* thread bound to FPU-full CPU set */
    +#define TIF_LOAD_WATCH 25 /* If set, load watch registers */
    #define TIF_SYSCALL_TRACE 31 /* syscall trace active */

    #define _TIF_SYSCALL_TRACE (1< @@ -138,6 +139,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
    #define _TIF_32BIT_REGS (1< #define _TIF_32BIT_ADDR (1< #define _TIF_FPUBOUND (1< +#define _TIF_LOAD_WATCH (1<
    /* work to do on interrupt/exception return */
    #define _TIF_WORK_MASK (0x0000ffef & ~_TIF_SECCOMP)
    diff --git a/include/asm-mips/watch.h b/include/asm-mips/watch.h
    new file mode 100644
    index 0000000..ca79f5a
    --- /dev/null
    +++ b/include/asm-mips/watch.h
    @@ -0,0 +1,32 @@
    +/*
    + * This file is subject to the terms and conditions of the GNU General Public
    + * License. See the file "COPYING" in the main directory of this archive
    + * for more details.
    + *
    + * Copyright (C) 2008 David Daney
    + */
    +#ifndef _ASM_WATCH_H
    +#define _ASM_WATCH_H
    +
    +#include
    +
    +#include
    +
    +#ifdef CONFIG_HARDWARE_WATCHPOINTS
    +void mips_install_watch_registers(void);
    +void mips_read_watch_registers(void);
    +void mips_clear_watch_registers(void);
    +void mips_probe_watch_registers(struct cpuinfo_mips *c);
    +
    +#define __restore_watch() do { \
    + if (unlikely(test_bit(TIF_LOAD_WATCH, \
    + &current_thread_info()->flags))) { \
    + mips_install_watch_registers(); \
    + } \
    +} while (0)
    +
    +#else
    +#define __restore_watch() do {} while (0)
    +#endif
    +
    +#endif /* _ASM_WATCH_H */
    --
    1.5.5

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  5. [PATCH 4/6] Watch exception handling for HARDWARE_WATCHPOINTS.

    Watch exception handling for HARDWARE_WATCHPOINTS.

    Here we hook up the watch exception handler so that it sends SIGTRAP when
    the hardware watch registers are triggered.

    Signed-off-by: David Daney
    ---
    arch/mips/kernel/genex.S | 4 ++++
    arch/mips/kernel/traps.c | 14 ++++++++++++++
    2 files changed, 18 insertions(+), 0 deletions(-)

    diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
    index c6ada98..15a9bde 100644
    --- a/arch/mips/kernel/genex.S
    +++ b/arch/mips/kernel/genex.S
    @@ -416,7 +416,11 @@ NESTED(nmi_handler, PT_SIZE, sp)
    BUILD_HANDLER tr tr sti silent /* #13 */
    BUILD_HANDLER fpe fpe fpe silent /* #15 */
    BUILD_HANDLER mdmx mdmx sti silent /* #22 */
    +#ifdef CONFIG_HARDWARE_WATCHPOINTS
    + BUILD_HANDLER watch watch sti silent /* #23 */
    +#else
    BUILD_HANDLER watch watch sti verbose /* #23 */
    +#endif
    BUILD_HANDLER mcheck mcheck cli verbose /* #24 */
    BUILD_HANDLER mt mt sti silent /* #25 */
    BUILD_HANDLER dsp dsp sti silent /* #26 */
    diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
    index 824b187..22bb053 100644
    --- a/arch/mips/kernel/traps.c
    +++ b/arch/mips/kernel/traps.c
    @@ -39,6 +39,7 @@
    #include
    #include
    #include
    +#include
    #include
    #include
    #include
    @@ -871,6 +872,18 @@ asmlinkage void do_mdmx(struct pt_regs *regs)

    asmlinkage void do_watch(struct pt_regs *regs)
    {
    +#ifdef CONFIG_HARDWARE_WATCHPOINTS
    + /*
    + * If the current thread has the watch registers loaded, save
    + * their values and send SIGTRAP. Otherwise another thread
    + * left the registers set, clear them and continue.
    + */
    + if (test_tsk_thread_flag(current, TIF_LOAD_WATCH)) {
    + mips_read_watch_registers();
    + force_sig(SIGTRAP, current);
    + } else
    + mips_clear_watch_registers();
    +#else
    if (board_watchpoint_handler) {
    (*board_watchpoint_handler)(regs);
    return;
    @@ -883,6 +896,7 @@ asmlinkage void do_watch(struct pt_regs *regs)
    dump_tlb_all();
    show_regs(regs);
    panic("Caught WATCH exception - probably caused by stack overflow.");
    +#endif
    }

    asmlinkage void do_mcheck(struct pt_regs *regs)
    --
    1.5.5

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  6. [PATCH 5/6] Scheduler support for HARDWARE_WATCHPOINTS.

    Scheduler support for HARDWARE_WATCHPOINTS.

    Here we hook up the scheduler. Whenever we switch to a new process,
    we check to see if the watch registers should be installed, and do it
    if needed.

    Signed-off-by: David Daney
    ---
    include/asm-mips/system.h | 2 ++
    1 files changed, 2 insertions(+), 0 deletions(-)

    diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
    index a944eda..cd30f83 100644
    --- a/include/asm-mips/system.h
    +++ b/include/asm-mips/system.h
    @@ -20,6 +20,7 @@
    #include
    #include
    #include
    +#include
    #include


    @@ -76,6 +77,7 @@ do { \
    __restore_dsp(current); \
    if (cpu_has_userlocal) \
    write_c0_userlocal(current_thread_info()->tp_value); \
    + __restore_watch(); \
    } while (0)

    static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
    --
    1.5.5

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  7. [PATCH 6/6] Ptrace support for HARDWARE_WATCHPOINTS.

    Ptrace support for HARDWARE_WATCHPOINTS

    This is the final part of the watch register patch. Here we hook up
    ptrace so that the user space debugger (gdb), can set and read the
    registers.

    Signed-off-by: David Daney
    ---
    arch/mips/kernel/ptrace.c | 93 +++++++++++++++++++++++++++++++++++++++++++++
    include/asm-mips/ptrace.h | 31 +++++++++++++++
    2 files changed, 124 insertions(+), 0 deletions(-)

    diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
    index 35234b9..8e86134 100644
    --- a/arch/mips/kernel/ptrace.c
    +++ b/arch/mips/kernel/ptrace.c
    @@ -46,7 +46,12 @@
    */
    void ptrace_disable(struct task_struct *child)
    {
    +#ifdef CONFIG_HARDWARE_WATCHPOINTS
    + /* Don't load the watchpoint registers for the ex-child. */
    + clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
    +#else
    /* Nothing to do.. */
    +#endif
    }

    /*
    @@ -167,6 +172,84 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
    return 0;
    }

    +#ifdef CONFIG_HARDWARE_WATCHPOINTS
    +static int ptrace_get_watch_regs(struct task_struct *child,
    + struct pt_watch_regs __user *addr)
    +{
    + enum pt_watch_style style;
    + int i;
    +
    + if (!cpu_has_watch)
    + return -EIO;
    + if (!access_ok(VERIFY_WRITE, addr, sizeof(struct pt_watch_regs)))
    + return -EIO;
    +
    +#ifdef CONFIG_32BIT
    + style = pt_watch_style_mips32;
    +#define WATCH_STYLE mips32
    +#else
    + style = pt_watch_style_mips64;
    +#define WATCH_STYLE mips64
    +#endif
    +
    + __put_user(style, &addr->style);
    + __put_user(current_cpu_data.watch_reg_count,
    + &addr->WATCH_STYLE.num_valid);
    + __put_user(current_cpu_data.watch_reg_mask,
    + &addr->WATCH_STYLE.reg_mask);
    + __put_user(current_cpu_data.watch_reg_irw,
    + &addr->WATCH_STYLE.irw_mask);
    + for (i = 0; i < current_cpu_data.watch_reg_count; i++) {
    + __put_user(child->thread.watch.mips3264.watchlo[i],
    + &addr->WATCH_STYLE.watchlo[i]);
    + __put_user(child->thread.watch.mips3264.watchhi[i] & 0xfff,
    + &addr->WATCH_STYLE.watchhi[i]);
    + }
    +
    + return 0;
    +}
    +
    +static int ptrace_set_watch_regs(struct task_struct *child,
    + struct pt_watch_regs __user *addr)
    +{
    + int i;
    + int watch_active = 0;
    + unsigned long lt[NUM_WATCH_REGS];
    + unsigned int ht[NUM_WATCH_REGS];
    +
    + if (!cpu_has_watch)
    + return -EIO;
    + if (!access_ok(VERIFY_READ, addr, sizeof(struct pt_watch_regs)))
    + return -EIO;
    + /* Check the values. */
    + for (i = 0; i < NUM_WATCH_REGS; i++) {
    + __get_user(lt[i], &addr->WATCH_STYLE.watchlo[i]);
    + if (lt[i] & __UA_LIMIT)
    + return -EINVAL;
    +
    + __get_user(ht[i], &addr->WATCH_STYLE.watchhi[i]);
    + if (ht[i] & ~0xff8)
    + return -EINVAL;
    + }
    + /* Install them. */
    + for (i = 0; i < NUM_WATCH_REGS; i++) {
    + if (lt[i] & 7)
    + watch_active = 1;
    + child->thread.watch.mips3264.watchlo[i] = lt[i];
    + /* Set the G bit. */
    + child->thread.watch.mips3264.watchhi[i] = ht[i] | 0x40000000;
    + }
    +
    + if (watch_active)
    + set_tsk_thread_flag(child, TIF_LOAD_WATCH);
    + else
    + clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
    +
    + return 0;
    +}
    +
    +#endif /* CONFIG_HARDWARE_WATCHPOINTS */
    +
    long arch_ptrace(struct task_struct *child, long request, long addr, long data)
    {
    int ret;
    @@ -439,7 +522,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
    ret = put_user(task_thread_info(child)->tp_value,
    (unsigned long __user *) data);
    break;
    +#ifdef CONFIG_HARDWARE_WATCHPOINTS
    + case PTRACE_GET_WATCH_REGS:
    + ret = ptrace_get_watch_regs(child,
    + (struct pt_watch_regs __user *) addr);
    + break;

    + case PTRACE_SET_WATCH_REGS:
    + ret = ptrace_set_watch_regs(child,
    + (struct pt_watch_regs __user *) addr);
    + break;
    +#endif
    default:
    ret = ptrace_request(child, request, addr, data);
    break;
    diff --git a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h
    index 786f7e3..d8d821d 100644
    --- a/include/asm-mips/ptrace.h
    +++ b/include/asm-mips/ptrace.h
    @@ -71,6 +71,37 @@ struct pt_regs {
    #define PTRACE_POKEDATA_3264 0xc3
    #define PTRACE_GET_THREAD_AREA_3264 0xc4

    +/* Read and write watchpoint registers. */
    +enum pt_watch_style {
    + pt_watch_style_mips32,
    + pt_watch_style_mips64
    +};
    +struct mips32_watch_regs {
    + uint32_t watchlo[8];
    + uint32_t watchhi[8];
    + uint32_t num_valid;
    + uint32_t reg_mask;
    + uint32_t irw_mask;
    +};
    +struct mips64_watch_regs {
    + uint64_t watchlo[8];
    + uint32_t watchhi[8];
    + uint32_t num_valid;
    + uint32_t reg_mask;
    + uint32_t irw_mask;
    +};
    +
    +struct pt_watch_regs {
    + enum pt_watch_style style;
    + union {
    + struct mips32_watch_regs mips32;
    + struct mips32_watch_regs mips64;
    + };
    +};
    +
    +#define PTRACE_GET_WATCH_REGS 0xd0
    +#define PTRACE_SET_WATCH_REGS 0xd1
    +
    #ifdef __KERNEL__

    #include
    --
    1.5.5

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

+ Reply to Thread