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.