Yes It's known issue.
On Mon, 05 May 2008 13:06:11 +0300
Avi Nehori <[EMAIL PROTECTED]> wrote:

> Hi,
> I'm trying to set a watch point with bpha as follows :
> bpha address dataw 4
> but the watchpoint is never called when the memory address is changed.
> is it a know bug ?
> is there a patch ?

  Here is my previous mail 
(http://oss.sgi.com/archives/kdb/2007-11/msg00037.html) with patch that fixes 
bpha problem:
  Global HW BP don't work:
1) Install global HW BP
[EMAIL PROTECTED]:~#
[EMAIL PROTECTED]:~# D
Entering kdb (current=0xc04433a0, pid 0) on processor 0 due to Keyboard Entry
[0]kdb> bpha do_sync  
Forced Instruction(Register) BP #0 at 0xc0181539 (do_sync)
    is enabled in dr0 globally
[0]kdb> go  

-bash: D: command not found
[EMAIL PROTECTED]:~#

1) Try CPU 0
[EMAIL PROTECTED]:~#
[EMAIL PROTECTED]:~# taskset -c 0 sync
Instruction(Register) breakpoint #0 at 0xc0181539
0xc0181539 do_sync:         push   %ebx

Entering kdb (0xc1b6d030, pid 1319) on processor 0 due to Debug @ 0xc0181539
[0]kdb> go  
[EMAIL PROTECTED]:~#
- OK

1) Try CPU 1
[EMAIL PROTECTED]:~#
[EMAIL PROTECTED]:~# taskset -c 1 sync
[EMAIL PROTECTED]:~#
- Doesn't work.

Signed-off-by: Konstantin Baydarov <[EMAIL PROTECTED]>
Description:
This patch adds support for global hardware breakpoints to KDB on x86
targets.  Hardware breakpoints are installed by setting per CPU db
registers. So to make a hardware breakpoint global it should be
installed in db registers on every CPU in system.  So global hw bp
can't be handle by kdb_bp_install_global and kdb_bp_remove_global
because these functions are called only on "monarch" CPU,
kdb_bp_install_local and kdb_bp_remove_local should be used instead
because these are called for all CPUs.

Main changes:
  - kdb_hardbreaks[KDB_MAXHARDBPT] - The processor architecture
    hardware breakpoint registers descriptors is defined for every
    CPU:
      static kdbhard_bp_t kdb_hardbreaks[NR_CPUS][KDB_MAXHARDBPT];

  - "kdb_bp_t" (main breakpint structure) contains hardware
    breakpoint registers for every CPU:
      kdbhard_bp_t*     bp_hard[NR_CPUS];

  - global hardware breakpoint installation and removal is handled
    by kdb_bp_install_local and kdb_bp_remove_local which are
    executed on every CPU

  - kdba_allocbp andkdba_freebp are static, now kdba_alloc_hwbp and
    kdba_free_hwbp are used for allocating/freeing hardware breakpoint
    registers.  If the hardware breakpoint is global then
    kdba_alloc_hwbp tries to allocate hardware breakpoint registers on
    every CPU. If there is no free hardware breakpoint on a CPU the
    allocation fails.

  - bph_installed was added to the hardware breakpoint descriptor to
    track per CPU hardware breakpoint installation.

  Patch against kernel 2.6.24-rc2

Index: linux-2.6.24-rc2/arch/x86/kdb/kdba_bp_32.c
===================================================================
--- linux-2.6.24-rc2.orig/arch/x86/kdb/kdba_bp_32.c
+++ linux-2.6.24-rc2/arch/x86/kdb/kdba_bp_32.c
@@ -22,10 +22,10 @@ static char *kdba_rwtypes[] = { "Instruc
 
 /*
  * Table describing processor architecture hardware
- * breakpoint registers.
+ * breakpoint registers for every CPU.
  */
 
-static kdbhard_bp_t kdb_hardbreaks[KDB_MAXHARDBPT];
+static kdbhard_bp_t kdb_hardbreaks[NR_CPUS][KDB_MAXHARDBPT];
 
 /*
  * kdba_db_trap
@@ -75,6 +75,7 @@ kdba_db_trap(struct pt_regs *regs, int e
        int i;
        kdb_dbtrap_t rv = KDB_DB_BPT;
        kdb_bp_t *bp;
+       int cpu = smp_processor_id();
 
        if (KDB_NULL_REGS(regs))
                return KDB_DB_NOBPT;
@@ -103,8 +104,12 @@ kdba_db_trap(struct pt_regs *regs, int e
                                        kdb_printf("bp for this cpu\n");
                                if (bp->bp_delayed) {
                                        bp->bp_delayed = 0;
-                                       if (KDB_DEBUG(BP))
+                                       if (KDB_DEBUG(BP)){
+                                               /* Can't be hw breakpoint */
+                                               if (bp->bp_hardtype)
+                                                       kdb_printf("kdb: Error 
- hw bp delayed\n");
                                                kdb_printf("kdba_installbp\n");
+                                       }
                                        kdba_installbp(regs, bp);
                                        if (!KDB_STATE(DOING_SS)) {
                                                regs->eflags &= ~EF_TF;
@@ -211,8 +216,8 @@ handle:
        for(i=0, bp=kdb_breakpoints; i<KDB_MAXBPT; i++, bp++) {
                if (!(bp->bp_free)
                 && (bp->bp_global || bp->bp_cpu == smp_processor_id())
-                && (bp->bp_hard)
-                && (bp->bp_hard->bph_reg == reg)) {
+                && (bp->bp_hard[cpu])
+                && (bp->bp_hard[cpu]->bph_reg == reg)) {
                        /*
                         * Hit this breakpoint.
                         */
@@ -438,12 +443,18 @@ kdba_printbpreg(kdbhard_bp_t *bph)
 void
 kdba_printbp(kdb_bp_t *bp)
 {
+       int cpu;
+
        kdb_printf("\n    is enabled");
        if (bp->bp_hardtype) {
-               kdba_printbpreg(bp->bp_hard);
-               if (bp->bp_hard->bph_mode != 0) {
+               if (bp->bp_global)
+                       cpu = smp_processor_id();
+               else
+                       cpu = bp->bp_cpu;
+               kdba_printbpreg(bp->bp_hard[cpu]);
+               if (bp->bp_hard[cpu]->bph_mode != 0) {
                        kdb_printf(" for %d bytes",
-                                  bp->bp_hard->bph_length+1);
+                                  bp->bp_hard[cpu]->bph_length+1);
                }
        }
 }
@@ -556,7 +567,7 @@ kdba_parsebp(int argc, const char **argv
 /*
  * kdba_allocbp
  *
- *     Associate a hardware register with a breakpoint.
+ *     Allocate hw register for bp on specific CPU
  *
  * Parameters:
  *     None.
@@ -570,13 +581,14 @@ kdba_parsebp(int argc, const char **argv
  * Remarks:
  */
 
-kdbhard_bp_t *
-kdba_allocbp(kdbhard_bp_t *bph, int *diagp)
+static kdbhard_bp_t *
+kdba_allocbp(kdbhard_bp_t *bph, int *diagp, unsigned int cpu)
 {
        int i;
        kdbhard_bp_t *newbph;
 
-       for(i=0,newbph=kdb_hardbreaks; i < KDB_MAXHARDBPT; i++, newbph++) {
+       for(i=0; i < KDB_MAXHARDBPT; i++) {
+               newbph=&(kdb_hardbreaks[cpu][i]);
                if (newbph->bph_free) {
                        break;
                }
@@ -608,9 +620,49 @@ kdba_allocbp(kdbhard_bp_t *bph, int *dia
 }
 
 /*
+ * kdba_alloc_hwbp
+ *
+ *     Associate a hardware registers with a breakpoint.
+ *     If hw bp is global hw registers descriptor will be allocated
+ *     on every CPU.
+ *
+ * Parameters:
+ *     bp - hardware bp
+ *     diagp - pointer to variable that will store error when
+ *     function complete
+ * Outputs:
+ *     None.
+ * Returns:
+ *     None
+ * Locking:
+ *     None.
+ * Remarks:
+ *     Should be called with correct bp->bp_template
+ */
+
+void
+kdba_alloc_hwbp(kdb_bp_t *bp, int *diagp)
+{
+       int i;
+
+       if (bp->bp_global){
+               for (i = 0; i < NR_CPUS; ++i) {
+                       if (!cpu_online(i))
+                               continue;
+                       bp->bp_hard[i] = kdba_allocbp(&bp->bp_template, diagp, 
i);
+                       if (*diagp)
+                               break;
+               }
+       } else {
+               bp->bp_hard[bp->bp_cpu] = kdba_allocbp(&bp->bp_template, diagp, 
bp->bp_cpu);
+       }
+       bp->bp_hardtype = 1;
+}
+
+/*
  * kdba_freebp
  *
- *     Deallocate a hardware breakpoint
+ *     Deallocate hw registers descriptor for bp on specific CPU
  *
  * Parameters:
  *     None.
@@ -623,13 +675,57 @@ kdba_allocbp(kdbhard_bp_t *bph, int *dia
  * Remarks:
  */
 
-void
+static void
 kdba_freebp(kdbhard_bp_t *bph)
 {
        bph->bph_free = 1;
 }
 
 /*
+ * kdba_free_hwbp
+ *
+ *     Frees allocated hw registers descriptors for bp.
+ *     If hw bp is global, hw registers descriptors will be freed
+ *     on every CPU.
+ *
+ * Parameters:
+ *     bp - hardware bp
+ * Outputs:
+ *     None.
+ * Returns:
+ *     None
+ * Locking:
+ *     None.
+ * Remarks:
+ *     Should be called with correct bp->bp_template
+ */
+
+void
+kdba_free_hwbp(kdb_bp_t *bp)
+{
+       int i;
+
+       /* When kernel enters KDB, first, all local bps
+        * are removed, so here we don't need to clear
+        * debug registers.
+        */
+
+       if (bp->bp_global){
+               for (i = 0; i < NR_CPUS; ++i) {
+                       if (!cpu_online(i))
+                               continue;
+                       if (bp->bp_hard[i])
+                               kdba_freebp(bp->bp_hard[i]);
+                       bp->bp_hard[i] = 0;
+               }
+       } else {
+               kdba_freebp(bp->bp_hard[bp->bp_cpu]);
+               bp->bp_hard[bp->bp_cpu] = NULL;
+       }
+       bp->bp_hardtype = 0;
+}
+
+/*
  * kdba_initbp
  *
  *     Initialize the breakpoint table for the hardware breakpoint
@@ -653,7 +749,7 @@ kdba_freebp(kdbhard_bp_t *bph)
 void
 kdba_initbp(void)
 {
-       int i;
+       int i,j;
        kdbhard_bp_t *bph;
 
        /*
@@ -662,9 +758,15 @@ kdba_initbp(void)
 
        memset(kdb_hardbreaks, '\0', sizeof(kdb_hardbreaks));
 
-       for(i=0,bph=kdb_hardbreaks; i<KDB_MAXHARDBPT; i++, bph++) {
-               bph->bph_reg = i;
-               bph->bph_free = 1;
+       for (i = 0; i < NR_CPUS; ++i) {
+               /* Called early so we don't know actual
+                * ammount of CPUs
+                */
+               for(j=0; j < KDB_MAXHARDBPT; j++) {
+                       bph=&(kdb_hardbreaks[i][j]);
+                       bph->bph_reg = j;
+                       bph->bph_free = 1;
+               }
        }
 }
 
@@ -698,6 +800,8 @@ kdba_initbp(void)
 int
 kdba_installbp(struct pt_regs *regs, kdb_bp_t *bp)
 {
+       int cpu = smp_processor_id();
+
        /*
         * Install the breakpoint, if it is not already installed.
         */
@@ -707,15 +811,27 @@ kdba_installbp(struct pt_regs *regs, kdb
        }
        if (!KDB_STATE(SSBPT))
                bp->bp_delay = 0;
-       if (!bp->bp_installed) {
-               if (bp->bp_hardtype) {
+
+       if (bp->bp_hardtype) {
+               if (KDB_DEBUG(BP) && !bp->bp_global && cpu != bp->bp_cpu){
+                       kdb_printf("kdba_removebp: cpu != bp->bp_cpu for local 
hw bp\n");
+               }
+
+               if (KDB_DEBUG(BP) && !bp->bp_hard[cpu]){
+                       kdb_printf("kdba_removebp: Error - 
bp_hard[smp_processor_id()] is emply\n");
+                       return 1;
+               }
+
+               if (!bp->bp_hard[cpu]->bph_installed){
                        kdba_installdbreg(bp);
-                       bp->bp_installed = 1;
+                       bp->bp_hard[cpu]->bph_installed = 1;
                        if (KDB_DEBUG(BP)) {
                                kdb_printf("kdba_installbp hardware reg %ld at 
" kdb_bfd_vma_fmt "\n",
-                                          bp->bp_hard->bph_reg, bp->bp_addr);
+                                  bp->bp_hard[cpu]->bph_reg, bp->bp_addr);
                        }
-               } else if (bp->bp_delay) {
+               }
+       } else if (!bp->bp_installed) {
+               if (bp->bp_delay) {
                        if (KDB_DEBUG(BP))
                                kdb_printf("kdba_installbp delayed bp\n");
                        kdba_handle_bp(regs, bp);
@@ -753,6 +869,8 @@ kdba_installbp(struct pt_regs *regs, kdb
 int
 kdba_removebp(kdb_bp_t *bp)
 {
+       int cpu = smp_processor_id();
+
        /*
         * For hardware breakpoints, remove it from the active register,
         * for software breakpoints, restore the instruction stream.
@@ -760,20 +878,36 @@ kdba_removebp(kdb_bp_t *bp)
        if (KDB_DEBUG(BP)) {
                kdb_printf("kdba_removebp bp_installed %d\n", bp->bp_installed);
        }
-       if (bp->bp_installed) {
-               if (bp->bp_hardtype) {
+
+       if (bp->bp_hardtype) {
+               if (KDB_DEBUG(BP) && !bp->bp_global && cpu != bp->bp_cpu){
+                       kdb_printf("kdba_removebp: cpu != bp->bp_cpu for local 
hw bp\n");
+               }
+
+               if (KDB_DEBUG(BP) && !bp->bp_hard[cpu]){
+                       kdb_printf("kdba_removebp: Error - 
bp_hard[smp_processor_id()] is emply\n");
+                       return 1;
+               }
+
+               if (KDB_DEBUG(BP)) {
+                       kdb_printf("kdb: removing hardware reg %ld at " 
kdb_bfd_vma_fmt "\n",
+                                  bp->bp_hard[cpu]->bph_reg, bp->bp_addr);
+               }
+
+               if (bp->bp_hard[cpu]->bph_installed){
                        if (KDB_DEBUG(BP)) {
-                               kdb_printf("kdb: removing hardware reg %ld at " 
kdb_bfd_vma_fmt "\n",
-                                          bp->bp_hard->bph_reg, bp->bp_addr);
+                               kdb_printf("kdba_installbp hardware reg %ld at 
" kdb_bfd_vma_fmt "\n",
+                                  bp->bp_hard[cpu]->bph_reg, bp->bp_addr);
                        }
                        kdba_removedbreg(bp);
-               } else {
-                       if (KDB_DEBUG(BP))
-                               kdb_printf("kdb: restoring instruction 0x%x at 
" kdb_bfd_vma_fmt "\n",
-                                          bp->bp_inst, bp->bp_addr);
-                       if (kdb_putword(bp->bp_addr, bp->bp_inst, 1))
-                               return(1);
+                       bp->bp_hard[cpu]->bph_installed = 0;
                }
+       } else if (bp->bp_installed) {
+               if (KDB_DEBUG(BP))
+                       kdb_printf("kdb: restoring instruction 0x%x at " 
kdb_bfd_vma_fmt "\n",
+                                  bp->bp_inst, bp->bp_addr);
+               if (kdb_putword(bp->bp_addr, bp->bp_inst, 1))
+                       return(1);
                bp->bp_installed = 0;
        }
        return(0);
Index: linux-2.6.24-rc2/arch/x86/kdb/kdbasupport_32.c
===================================================================
--- linux-2.6.24-rc2.orig/arch/x86/kdb/kdbasupport_32.c
+++ linux-2.6.24-rc2/arch/x86/kdb/kdbasupport_32.c
@@ -82,7 +82,7 @@ kdba_putdr(int regnum, kdb_machreg_t con
        }
 }
 
-static kdb_machreg_t
+kdb_machreg_t
 kdba_getdr(int regnum)
 {
        kdb_machreg_t contents = 0;
@@ -142,40 +142,42 @@ kdba_putdr7(kdb_machreg_t contents)
 void
 kdba_installdbreg(kdb_bp_t *bp)
 {
+       int cpu = smp_processor_id();
+
        kdb_machreg_t dr7;
 
        dr7 = kdba_getdr7();
 
-       kdba_putdr(bp->bp_hard->bph_reg, bp->bp_addr);
+       kdba_putdr(bp->bp_hard[cpu]->bph_reg, bp->bp_addr);
 
        dr7 |= DR7_GE;
        if (cpu_has_de)
                set_in_cr4(X86_CR4_DE);
 
-       switch (bp->bp_hard->bph_reg){
+       switch (bp->bp_hard[cpu]->bph_reg){
        case 0:
-               DR7_RW0SET(dr7,bp->bp_hard->bph_mode);
-               DR7_LEN0SET(dr7,bp->bp_hard->bph_length);
+               DR7_RW0SET(dr7,bp->bp_hard[cpu]->bph_mode);
+               DR7_LEN0SET(dr7,bp->bp_hard[cpu]->bph_length);
                DR7_G0SET(dr7);
                break;
        case 1:
-               DR7_RW1SET(dr7,bp->bp_hard->bph_mode);
-               DR7_LEN1SET(dr7,bp->bp_hard->bph_length);
+               DR7_RW1SET(dr7,bp->bp_hard[cpu]->bph_mode);
+               DR7_LEN1SET(dr7,bp->bp_hard[cpu]->bph_length);
                DR7_G1SET(dr7);
                break;
        case 2:
-               DR7_RW2SET(dr7,bp->bp_hard->bph_mode);
-               DR7_LEN2SET(dr7,bp->bp_hard->bph_length);
+               DR7_RW2SET(dr7,bp->bp_hard[cpu]->bph_mode);
+               DR7_LEN2SET(dr7,bp->bp_hard[cpu]->bph_length);
                DR7_G2SET(dr7);
                break;
        case 3:
-               DR7_RW3SET(dr7,bp->bp_hard->bph_mode);
-               DR7_LEN3SET(dr7,bp->bp_hard->bph_length);
+               DR7_RW3SET(dr7,bp->bp_hard[cpu]->bph_mode);
+               DR7_LEN3SET(dr7,bp->bp_hard[cpu]->bph_length);
                DR7_G3SET(dr7);
                break;
        default:
                kdb_printf("kdb: Bad debug register!! %ld\n",
-                          bp->bp_hard->bph_reg);
+                          bp->bp_hard[cpu]->bph_reg);
                break;
        }
 
@@ -188,11 +190,12 @@ kdba_removedbreg(kdb_bp_t *bp)
 {
        int regnum;
        kdb_machreg_t dr7;
+       int cpu = smp_processor_id();
 
-       if (!bp->bp_hard)
+       if (!bp->bp_hard[cpu])
                return;
 
-       regnum = bp->bp_hard->bph_reg;
+       regnum = bp->bp_hard[cpu]->bph_reg;
 
        dr7 = kdba_getdr7();
 
Index: linux-2.6.24-rc2/include/linux/kdbprivate.h
===================================================================
--- linux-2.6.24-rc2.orig/include/linux/kdbprivate.h
+++ linux-2.6.24-rc2/include/linux/kdbprivate.h
@@ -204,7 +204,7 @@ typedef struct _kdb_bp {
 
        int             bp_cpu;         /* Cpu #  (if bp_global == 0) */
        kdbhard_bp_t    bp_template;    /* Hardware breakpoint template */
-       kdbhard_bp_t    *bp_hard;       /* Hardware breakpoint structure */
+       kdbhard_bp_t*   bp_hard[NR_CPUS];       /* Hardware breakpoint 
structure */
        int             bp_adjust;      /* Adjustment to PC for real 
instruction */
 } kdb_bp_t;
 
@@ -219,8 +219,8 @@ extern kdb_bp_t kdb_breakpoints[/* KDB_M
         */
 extern void kdba_initbp(void);
 extern void kdba_printbp(kdb_bp_t *);
-extern kdbhard_bp_t *kdba_allocbp(kdbhard_bp_t *, int *);
-extern void kdba_freebp(kdbhard_bp_t *);
+extern void kdba_alloc_hwbp(kdb_bp_t *bp, int *diagp);
+extern void kdba_free_hwbp(kdb_bp_t *bp);
 extern int kdba_parsebp(int, const char**, int *, kdb_bp_t*);
 extern char *kdba_bptype(kdbhard_bp_t *);
 extern void kdba_setsinglestep(struct pt_regs *);
Index: linux-2.6.24-rc2/kdb/kdb_bp.c
===================================================================
--- linux-2.6.24-rc2.orig/kdb/kdb_bp.c
+++ linux-2.6.24-rc2/kdb/kdb_bp.c
@@ -54,8 +54,9 @@ kdb_bp_install_global(struct pt_regs *re
                        kdb_printf("kdb_bp_install_global bp %d bp_enabled %d 
bp_global %d\n",
                                i, kdb_breakpoints[i].bp_enabled, 
kdb_breakpoints[i].bp_global);
                }
+               /* Hw breakpoints local or global are installed in 
kdb_bp_install_local() */
                if (kdb_breakpoints[i].bp_enabled
-                && kdb_breakpoints[i].bp_global) {
+                && (kdb_breakpoints[i].bp_global && 
!kdb_breakpoints[i].bp_hardtype)) {
                        kdba_installbp(regs, &kdb_breakpoints[i]);
                }
        }
@@ -86,18 +87,32 @@ void
 kdb_bp_install_local(struct pt_regs *regs)
 {
        int i;
+       int do_install;
 
        for(i=0; i<KDB_MAXBPT; i++) {
+               do_install = 0;
+
                if (KDB_DEBUG(BP)) {
                        kdb_printf("kdb_bp_install_local bp %d bp_enabled %d 
bp_global %d cpu %d bp_cpu %d\n",
                                i, kdb_breakpoints[i].bp_enabled, 
kdb_breakpoints[i].bp_global,
                                smp_processor_id(), kdb_breakpoints[i].bp_cpu);
                }
-               if (kdb_breakpoints[i].bp_enabled
-                && kdb_breakpoints[i].bp_cpu == smp_processor_id()
-                && !kdb_breakpoints[i].bp_global){
-                       kdba_installbp(regs, &kdb_breakpoints[i]);
+
+               if(!kdb_breakpoints[i].bp_enabled)
+                       continue;
+
+               if (kdb_breakpoints[i].bp_hardtype){
+                       if(kdb_breakpoints[i].bp_cpu == smp_processor_id() ||
+                               kdb_breakpoints[i].bp_global)
+                                       do_install = 1;
+               } else {
+                       if(kdb_breakpoints[i].bp_cpu == smp_processor_id() &&
+                               !kdb_breakpoints[i].bp_global)
+                                       do_install = 1;
                }
+
+               if(do_install)
+                       kdba_installbp(regs, &kdb_breakpoints[i]);
        }
 }
 
@@ -127,8 +142,9 @@ kdb_bp_remove_global(void)
                        kdb_printf("kdb_bp_remove_global bp %d bp_enabled %d 
bp_global %d\n",
                                i, kdb_breakpoints[i].bp_enabled, 
kdb_breakpoints[i].bp_global);
                }
+               /* Hw breakpoints local or global are remove in 
kdb_bp_remove_local() */
                if (kdb_breakpoints[i].bp_enabled
-                && kdb_breakpoints[i].bp_global) {
+                && (kdb_breakpoints[i].bp_global && 
!kdb_breakpoints[i].bp_hardtype)) {
                        kdba_removebp(&kdb_breakpoints[i]);
                }
        }
@@ -155,18 +171,32 @@ void
 kdb_bp_remove_local(void)
 {
        int i;
+       int do_remove;
 
        for(i=KDB_MAXBPT-1; i>=0; i--) {
+               do_remove = 0;
+
                if (KDB_DEBUG(BP)) {
                        kdb_printf("kdb_bp_remove_local bp %d bp_enabled %d 
bp_global %d cpu %d bp_cpu %d\n",
                                i, kdb_breakpoints[i].bp_enabled, 
kdb_breakpoints[i].bp_global,
                                smp_processor_id(), kdb_breakpoints[i].bp_cpu);
                }
-               if (kdb_breakpoints[i].bp_enabled
-                && kdb_breakpoints[i].bp_cpu == smp_processor_id()
-                && !kdb_breakpoints[i].bp_global){
-                       kdba_removebp(&kdb_breakpoints[i]);
+
+               if (!kdb_breakpoints[i].bp_enabled)
+                       continue;
+
+               if (kdb_breakpoints[i].bp_hardtype){
+                       if((kdb_breakpoints[i].bp_cpu == smp_processor_id()) ||
+                               kdb_breakpoints[i].bp_global)
+                                       do_remove = 1;
+               } else {
+                       if(kdb_breakpoints[i].bp_cpu == smp_processor_id() &&
+                               !kdb_breakpoints[i].bp_global)
+                                       do_remove = 1;
                }
+
+               if (do_remove)
+                       kdba_removebp(&kdb_breakpoints[i]);
        }
 }
 
@@ -332,12 +362,13 @@ kdb_bp(int argc, const char **argv)
         * attempt to allocate a hardware register for it.
         */
        if (!bp->bp_template.bph_free) {
-               bp->bp_hard = kdba_allocbp(&bp->bp_template, &diag);
-               if (diag) {
+               kdba_alloc_hwbp(bp, &diag);
+               if (diag){
                        bp->bp_enabled = 0;
+                       bp->bp_hardtype = 0;
+                       kdba_free_hwbp(bp);
                        return diag;
                }
-               bp->bp_hardtype = 1;
        }
 
        kdb_printbp(bp, bpno);
@@ -432,11 +463,8 @@ kdb_bc(int argc, const char **argv)
 
                switch (cmd) {
                case KDBCMD_BC:
-                       if (bp->bp_hardtype) {
-                               kdba_freebp(bp->bp_hard);
-                               bp->bp_hard = NULL;
-                               bp->bp_hardtype = 0;
-                       }
+                       if (bp->bp_hardtype)
+                               kdba_free_hwbp(bp);
 
                        bp->bp_enabled = 0;
                        bp->bp_global = 0;
@@ -455,12 +483,14 @@ kdb_bc(int argc, const char **argv)
                         */
                        if (!bp->bp_template.bph_free
                         && !bp->bp_hardtype) {
-                               bp->bp_hard = kdba_allocbp(&bp->bp_template, 
&diag);
-                               if (diag) {
+                               kdba_alloc_hwbp(bp, &diag);
+                               if (diag){
                                        bp->bp_enabled = 0;
+                                       bp->bp_hardtype = 0;
+                                       kdba_free_hwbp(bp);
                                        return diag;
                                }
-                               bp->bp_hardtype = 1;
+
                        }
 
                        bp->bp_enabled = 1;
@@ -479,11 +509,9 @@ kdb_bc(int argc, const char **argv)
                         * give up the hardware register which is allocated
                         * to it.
                         */
-                       if (bp->bp_hardtype) {
-                               kdba_freebp(bp->bp_hard);
-                               bp->bp_hard = NULL;
-                               bp->bp_hardtype = 0;
-                       }
+
+                       if (bp->bp_hardtype)
+                               kdba_free_hwbp(bp);
 
                        bp->bp_enabled = 0;
 
Index: linux-2.6.24-rc2/include/asm-x86/kdbprivate_32.h
===================================================================
--- linux-2.6.24-rc2.orig/include/asm-x86/kdbprivate_32.h
+++ linux-2.6.24-rc2/include/asm-x86/kdbprivate_32.h
@@ -45,6 +45,7 @@ typedef struct _kdbhard_bp {
        unsigned int    bph_write:1;    /* Write Data breakpoint */
        unsigned int    bph_mode:2;     /* 0=inst, 1=write, 2=io, 3=read */
        unsigned int    bph_length:2;   /* 0=1, 1=2, 2=BAD, 3=4 (bytes) */
+       unsigned int    bph_installed;  /* flag: hw bp is installed */
 } kdbhard_bp_t;
 
 #define IA32_BREAKPOINT_INSTRUCTION    0xcc
Index: linux-2.6.24-rc2/arch/x86/kdb/kdba_bp_64.c
===================================================================
--- linux-2.6.24-rc2.orig/arch/x86/kdb/kdba_bp_64.c
+++ linux-2.6.24-rc2/arch/x86/kdb/kdba_bp_64.c
@@ -22,10 +22,10 @@ static char *kdba_rwtypes[] = { "Instruc
 
 /*
  * Table describing processor architecture hardware
- * breakpoint registers.
+ * breakpoint registers for every CPU.
  */
 
-kdbhard_bp_t   kdb_hardbreaks[KDB_MAXHARDBPT];
+static kdbhard_bp_t kdb_hardbreaks[NR_CPUS][KDB_MAXHARDBPT];
 
 /*
  * kdba_db_trap
@@ -75,6 +75,7 @@ kdba_db_trap(struct pt_regs *regs, int e
        int i;
        kdb_dbtrap_t rv = KDB_DB_BPT;
        kdb_bp_t *bp;
+       int cpu = smp_processor_id();
 
        if (KDB_NULL_REGS(regs))
                return KDB_DB_NOBPT;
@@ -103,8 +104,12 @@ kdba_db_trap(struct pt_regs *regs, int e
                                        kdb_printf("bp for this cpu\n");
                                if (bp->bp_delayed) {
                                        bp->bp_delayed = 0;
-                                       if (KDB_DEBUG(BP))
+                                       if (KDB_DEBUG(BP)){
+                                               /* Can't be hw breakpoint */
+                                               if (bp->bp_hardtype)
+                                                       kdb_printf("kdb: Error 
- hw bp delayed\n");
                                                kdb_printf("kdba_installbp\n");
+                                       }
                                        kdba_installbp(regs, bp);
                                        if (!KDB_STATE(DOING_SS)) {
                                                regs->eflags &= ~EF_TF;
@@ -211,8 +216,8 @@ handle:
        for(i=0, bp=kdb_breakpoints; i<KDB_MAXBPT; i++, bp++) {
                if (!(bp->bp_free)
                 && (bp->bp_global || bp->bp_cpu == smp_processor_id())
-                && (bp->bp_hard)
-                && (bp->bp_hard->bph_reg == reg)) {
+                && (bp->bp_hard[cpu])
+                && (bp->bp_hard[cpu]->bph_reg == reg)) {
                        /*
                         * Hit this breakpoint.
                         */
@@ -437,12 +442,18 @@ kdba_printbpreg(kdbhard_bp_t *bph)
 void
 kdba_printbp(kdb_bp_t *bp)
 {
+       int cpu;
+
        kdb_printf("\n    is enabled");
        if (bp->bp_hardtype) {
-               kdba_printbpreg(bp->bp_hard);
-               if (bp->bp_hard->bph_mode != 0) {
+               if (bp->bp_global)
+                       cpu = smp_processor_id();
+               else
+                       cpu = bp->bp_cpu;
+               kdba_printbpreg(bp->bp_hard[cpu]);
+               if (bp->bp_hard[cpu]->bph_mode != 0) {
                        kdb_printf(" for %d bytes",
-                                  bp->bp_hard->bph_length+1);
+                                  bp->bp_hard[cpu]->bph_length+1);
                }
        }
 }
@@ -555,7 +566,7 @@ kdba_parsebp(int argc, const char **argv
 /*
  * kdba_allocbp
  *
- *     Associate a hardware register with a breakpoint.
+ *     Allocate hw register for bp on specific CPU
  *
  * Parameters:
  *     None.
@@ -569,13 +580,14 @@ kdba_parsebp(int argc, const char **argv
  * Remarks:
  */
 
-kdbhard_bp_t *
-kdba_allocbp(kdbhard_bp_t *bph, int *diagp)
+static kdbhard_bp_t *
+kdba_allocbp(kdbhard_bp_t *bph, int *diagp, unsigned int cpu)
 {
        int i;
        kdbhard_bp_t *newbph;
 
-       for(i=0,newbph=kdb_hardbreaks; i < KDB_MAXHARDBPT; i++, newbph++) {
+       for(i=0; i < KDB_MAXHARDBPT; i++) {
+               newbph=&(kdb_hardbreaks[cpu][i]);
                if (newbph->bph_free) {
                        break;
                }
@@ -607,9 +619,49 @@ kdba_allocbp(kdbhard_bp_t *bph, int *dia
 }
 
 /*
+ * kdba_alloc_hwbp
+ *
+ *     Associate a hardware registers with a breakpoint.
+ *     If hw bp is global hw registers descriptor will be allocated
+ *     on every CPU.
+ *
+ * Parameters:
+ *     bp - hardware bp
+ *     diagp - pointer to variable that will store error when
+ *     function complete
+ * Outputs:
+ *     None.
+ * Returns:
+ *     None
+ * Locking:
+ *     None.
+ * Remarks:
+ *     Should be called with correct bp->bp_template
+ */
+
+void
+kdba_alloc_hwbp(kdb_bp_t *bp, int *diagp)
+{
+       int i;
+
+       if (bp->bp_global){
+               for (i = 0; i < NR_CPUS; ++i) {
+                       if (!cpu_online(i))
+                               continue;
+                       bp->bp_hard[i] = kdba_allocbp(&bp->bp_template, diagp, 
i);
+                       if (*diagp)
+                               break;
+               }
+       } else {
+               bp->bp_hard[bp->bp_cpu] = kdba_allocbp(&bp->bp_template, diagp, 
bp->bp_cpu);
+       }
+       bp->bp_hardtype = 1;
+}
+
+/*
  * kdba_freebp
  *
- *     Deallocate a hardware breakpoint
+ *     Deallocate hw registers descriptor for bp on specific CPU
  *
  * Parameters:
  *     None.
@@ -622,13 +674,57 @@ kdba_allocbp(kdbhard_bp_t *bph, int *dia
  * Remarks:
  */
 
-void
+static void
 kdba_freebp(kdbhard_bp_t *bph)
 {
        bph->bph_free = 1;
 }
 
 /*
+ * kdba_free_hwbp
+ *
+ *     Frees allocated hw registers descriptors for bp.
+ *     If hw bp is global, hw registers descriptors will be freed
+ *     on every CPU.
+ *
+ * Parameters:
+ *     bp - hardware bp
+ * Outputs:
+ *     None.
+ * Returns:
+ *     None
+ * Locking:
+ *     None.
+ * Remarks:
+ *     Should be called with correct bp->bp_template
+ */
+
+void
+kdba_free_hwbp(kdb_bp_t *bp)
+{
+       int i;
+
+       /* When kernel enters KDB, first, all local bps
+        * are removed, so here we don't need to clear
+        * debug registers.
+        */
+
+       if (bp->bp_global){
+               for (i = 0; i < NR_CPUS; ++i) {
+                       if (!cpu_online(i))
+                               continue;
+                       if (bp->bp_hard[i])
+                               kdba_freebp(bp->bp_hard[i]);
+                       bp->bp_hard[i] = 0;
+               }
+       } else {
+               kdba_freebp(bp->bp_hard[bp->bp_cpu]);
+               bp->bp_hard[bp->bp_cpu] = NULL;
+       }
+       bp->bp_hardtype = 0;
+}
+
+/*
  * kdba_initbp
  *
  *     Initialize the breakpoint table for the hardware breakpoint
@@ -652,7 +748,7 @@ kdba_freebp(kdbhard_bp_t *bph)
 void
 kdba_initbp(void)
 {
-       int i;
+       int i,j;
        kdbhard_bp_t *bph;
 
        /*
@@ -661,9 +757,15 @@ kdba_initbp(void)
 
        memset(kdb_hardbreaks, '\0', sizeof(kdb_hardbreaks));
 
-       for(i=0,bph=kdb_hardbreaks; i<KDB_MAXHARDBPT; i++, bph++) {
-               bph->bph_reg = i;
-               bph->bph_free = 1;
+       for (i = 0; i < NR_CPUS; ++i) {
+               /* Called early so we don't know actual
+                * ammount of CPUs
+                */
+               for(j=0; j < KDB_MAXHARDBPT; j++) {
+                       bph=&(kdb_hardbreaks[i][j]);
+                       bph->bph_reg = j;
+                       bph->bph_free = 1;
+               }
        }
 }
 
@@ -695,6 +797,8 @@ kdba_initbp(void)
 int
 kdba_installbp(struct pt_regs *regs, kdb_bp_t *bp)
 {
+       int cpu = smp_processor_id();
+
        /*
         * Install the breakpoint, if it is not already installed.
         */
@@ -704,15 +808,27 @@ kdba_installbp(struct pt_regs *regs, kdb
        }
        if (!KDB_STATE(SSBPT))
                bp->bp_delay = 0;
-       if (!bp->bp_installed) {
-               if (bp->bp_hardtype) {
+
+       if (bp->bp_hardtype) {
+               if (KDB_DEBUG(BP) && !bp->bp_global && cpu != bp->bp_cpu){
+                       kdb_printf("kdba_removebp: cpu != bp->bp_cpu for local 
hw bp\n");
+               }
+
+               if (KDB_DEBUG(BP) && !bp->bp_hard[cpu]){
+                       kdb_printf("kdba_removebp: Error - 
bp_hard[smp_processor_id()] is emply\n");
+                       return 1;
+               }
+
+               if (!bp->bp_hard[cpu]->bph_installed){
                        kdba_installdbreg(bp);
-                       bp->bp_installed = 1;
+                       bp->bp_hard[cpu]->bph_installed = 1;
                        if (KDB_DEBUG(BP)) {
                                kdb_printf("kdba_installbp hardware reg %ld at 
" kdb_bfd_vma_fmt "\n",
-                                          bp->bp_hard->bph_reg, bp->bp_addr);
+                                  bp->bp_hard[cpu]->bph_reg, bp->bp_addr);
                        }
-               } else if (bp->bp_delay) {
+               }
+       } else if (!bp->bp_installed) {
+               if (bp->bp_delay) {
                        if (KDB_DEBUG(BP))
                                kdb_printf("kdba_installbp delayed bp\n");
                        kdba_handle_bp(regs, bp);
@@ -750,6 +866,8 @@ kdba_installbp(struct pt_regs *regs, kdb
 int
 kdba_removebp(kdb_bp_t *bp)
 {
+       int cpu = smp_processor_id();
+
        /*
         * For hardware breakpoints, remove it from the active register,
         * for software breakpoints, restore the instruction stream.
@@ -757,20 +875,36 @@ kdba_removebp(kdb_bp_t *bp)
        if (KDB_DEBUG(BP)) {
                kdb_printf("kdba_removebp bp_installed %d\n", bp->bp_installed);
        }
-       if (bp->bp_installed) {
-               if (bp->bp_hardtype) {
+
+       if (bp->bp_hardtype) {
+               if (KDB_DEBUG(BP) && !bp->bp_global && cpu != bp->bp_cpu){
+                       kdb_printf("kdba_removebp: cpu != bp->bp_cpu for local 
hw bp\n");
+               }
+
+               if (KDB_DEBUG(BP) && !bp->bp_hard[cpu]){
+                       kdb_printf("kdba_removebp: Error - 
bp_hard[smp_processor_id()] is emply\n");
+                       return 1;
+               }
+
+               if (KDB_DEBUG(BP)) {
+                       kdb_printf("kdb: removing hardware reg %ld at " 
kdb_bfd_vma_fmt "\n",
+                                  bp->bp_hard[cpu]->bph_reg, bp->bp_addr);
+               }
+
+               if (bp->bp_hard[cpu]->bph_installed){
                        if (KDB_DEBUG(BP)) {
-                               kdb_printf("kdb: removing hardware reg %ld at " 
kdb_bfd_vma_fmt "\n",
-                                          bp->bp_hard->bph_reg, bp->bp_addr);
+                               kdb_printf("kdba_installbp hardware reg %ld at 
" kdb_bfd_vma_fmt "\n",
+                                  bp->bp_hard[cpu]->bph_reg, bp->bp_addr);
                        }
                        kdba_removedbreg(bp);
-               } else {
-                       if (KDB_DEBUG(BP))
-                               kdb_printf("kdb: restoring instruction 0x%x at 
" kdb_bfd_vma_fmt "\n",
-                                          bp->bp_inst, bp->bp_addr);
-                       if (kdb_putword(bp->bp_addr, bp->bp_inst, 1))
-                               return(1);
+                       bp->bp_hard[cpu]->bph_installed = 0;
                }
+       } else if (bp->bp_installed) {
+               if (KDB_DEBUG(BP))
+                       kdb_printf("kdb: restoring instruction 0x%x at " 
kdb_bfd_vma_fmt "\n",
+                                  bp->bp_inst, bp->bp_addr);
+               if (kdb_putword(bp->bp_addr, bp->bp_inst, 1))
+                       return(1);
                bp->bp_installed = 0;
        }
        return(0);
Index: linux-2.6.24-rc2/arch/x86/kdb/kdbasupport_64.c
===================================================================
--- linux-2.6.24-rc2.orig/arch/x86/kdb/kdbasupport_64.c
+++ linux-2.6.24-rc2/arch/x86/kdb/kdbasupport_64.c
@@ -55,40 +55,42 @@ kdba_putdr7(kdb_machreg_t contents)
 void
 kdba_installdbreg(kdb_bp_t *bp)
 {
+       int cpu = smp_processor_id();
+
        kdb_machreg_t   dr7;
 
        dr7 = kdba_getdr7();
 
-       kdba_putdr(bp->bp_hard->bph_reg, bp->bp_addr);
+       kdba_putdr(bp->bp_hard[cpu]->bph_reg, bp->bp_addr);
 
        dr7 |= DR7_GE;
        if (cpu_has_de)
                set_in_cr4(X86_CR4_DE);
 
-       switch (bp->bp_hard->bph_reg){
+       switch (bp->bp_hard[cpu]->bph_reg){
        case 0:
-               DR7_RW0SET(dr7,bp->bp_hard->bph_mode);
-               DR7_LEN0SET(dr7,bp->bp_hard->bph_length);
+               DR7_RW0SET(dr7,bp->bp_hard[cpu]->bph_mode);
+               DR7_LEN0SET(dr7,bp->bp_hard[cpu]->bph_length);
                DR7_G0SET(dr7);
                break;
        case 1:
-               DR7_RW1SET(dr7,bp->bp_hard->bph_mode);
-               DR7_LEN1SET(dr7,bp->bp_hard->bph_length);
+               DR7_RW1SET(dr7,bp->bp_hard[cpu]->bph_mode);
+               DR7_LEN1SET(dr7,bp->bp_hard[cpu]->bph_length);
                DR7_G1SET(dr7);
                break;
        case 2:
-               DR7_RW2SET(dr7,bp->bp_hard->bph_mode);
-               DR7_LEN2SET(dr7,bp->bp_hard->bph_length);
+               DR7_RW2SET(dr7,bp->bp_hard[cpu]->bph_mode);
+               DR7_LEN2SET(dr7,bp->bp_hard[cpu]->bph_length);
                DR7_G2SET(dr7);
                break;
        case 3:
-               DR7_RW3SET(dr7,bp->bp_hard->bph_mode);
-               DR7_LEN3SET(dr7,bp->bp_hard->bph_length);
+               DR7_RW3SET(dr7,bp->bp_hard[cpu]->bph_mode);
+               DR7_LEN3SET(dr7,bp->bp_hard[cpu]->bph_length);
                DR7_G3SET(dr7);
                break;
        default:
                kdb_printf("kdb: Bad debug register!! %ld\n",
-                          bp->bp_hard->bph_reg);
+                          bp->bp_hard[cpu]->bph_reg);
                break;
        }
 
@@ -101,11 +103,12 @@ kdba_removedbreg(kdb_bp_t *bp)
 {
        int             regnum;
        kdb_machreg_t   dr7;
+       int cpu = smp_processor_id();
 
-       if (!bp->bp_hard)
+       if (!bp->bp_hard[cpu])
                return;
 
-       regnum = bp->bp_hard->bph_reg;
+       regnum = bp->bp_hard[cpu]->bph_reg;
 
        dr7 = kdba_getdr7();
 
Index: linux-2.6.24-rc2/include/asm-x86/kdbprivate_64.h
===================================================================
--- linux-2.6.24-rc2.orig/include/asm-x86/kdbprivate_64.h
+++ linux-2.6.24-rc2/include/asm-x86/kdbprivate_64.h
@@ -45,10 +45,9 @@ typedef struct _kdbhard_bp {
        unsigned int    bph_write:1;    /* Write Data breakpoint */
        unsigned int    bph_mode:2;     /* 0=inst, 1=write, 2=io, 3=read */
        unsigned int    bph_length:2;   /* 0=1, 1=2, 2=BAD, 3=4 (bytes) */
+       unsigned int    bph_installed;  /* flag: hw bp is installed */
 } kdbhard_bp_t;
 
-extern kdbhard_bp_t    kdb_hardbreaks[/* KDB_MAXHARDBPT */];
-
 #define IA32_BREAKPOINT_INSTRUCTION    0xcc
 
 #define DR6_BT  0x00008000
---------------------------
Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe.

Reply via email to