bph / bpha not working.

Konstantin Baydarov kbaidarov at ru.mvista.com
Mon May 5 03:44:19 PDT 2008


  Yes It's known issue.
On Mon, 05 May 2008 13:06:11 +0300
Avi Nehori <anehori at checkpoint.com> 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
root at 192.168.2.10:~#
root at 192.168.2.10:~# 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
root at 192.168.2.10:~#

1) Try CPU 0
root at 192.168.2.10:~#
root at 192.168.2.10:~# 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  
root at 192.168.2.10:~#
- OK

1) Try CPU 1
root at 192.168.2.10:~#
root at 192.168.2.10:~# taskset -c 1 sync
root at 192.168.2.10:~#
- Doesn't work.

Signed-off-by: Konstantin Baydarov <kbaidarov at ru.mvista.com>
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.


More information about the kdb mailing list