Anshuman Khandual <khand...@linux.vnet.ibm.com> writes: > This patch enables support for hardware instruction breakpoints on POWER8 with > the help of a new register called CIABR (Completed Instruction Address > Breakpoint > Register). With this patch, single hardware instruction breakpoint can be > added > and cleared during any active xmon debug session. This hardware based > instruction > breakpoint mechanism works correctly along with the existing TRAP based > instruction > breakpoints available on xmon. Example usage as follows. > > (A) Start xmon: > $echo x > /proc/sysrq-trigger > SysRq : Entering xmon > cpu 0x0: Vector: 0 at [c000001f6c67f960] > pc: c000000000072078: .sysrq_handle_xmon+0x58/0x60 > lr: c000000000072078: .sysrq_handle_xmon+0x58/0x60 > sp: c000001f6c67fac0 > msr: 9000000000009032 > current = 0xc000001f6e709ac0 > paca = 0xc00000000fffa000 softe: 0 irq_happened: 0x00 > pid = 3250, comm = bash > enter ? for help > 0:mon> b > type address > > (B) Set the breakpoint: > 0:mon> ls .power_pmu_add > .power_pmu_add: c000000000078f50 > 0:mon> bi c000000000078f50 > 0:mon> b > type address > 1 inst c000000000078f50 .power_pmu_add+0x0/0x2e0 > 0:mon> ls .perf_event_interrupt > .perf_event_interrupt: c00000000007aee0 > 0:mon> bi c00000000007aee0 > One instruction breakpoint possible with CIABR > 0:mon> x > > (C) Run the workload (with the breakpoint): > $./perf record ls > cpu 0x2: Vector: d00 (Single Step) at [c000001f718133a0] > pc: c000000000078f54: .power_pmu_add+0x4/0x2e0 > lr: c000000000155be0: .event_sched_in+0x90/0x1d0 > sp: c000001f71813620 > msr: 9000000040109032 > current = 0xc000001f6ce30000 > paca = 0xc00000000fffa600 softe: 0 irq_happened: 0x01 > pid = 3270, comm = ls > std r22,-80(r1) > enter ? for help > > (D) Clear the breakpoint: > 2:mon> bc > All breakpoints cleared > 2:mon> x > [ perf record: Woken up 1 times to write data ] > [ perf record: Captured and wrote 0.002 MB perf.data (~66 samples) ] > > (E) Run the workload again (without any breakpoints): > $./perf record ls > [ perf record: Woken up 1 times to write data ] > [ perf record: Captured and wrote 0.001 MB perf.data (~61 samples) ] > > Signed-off-by: Anshuman Khandual <khand...@linux.vnet.ibm.com> > --- > arch/powerpc/xmon/xmon.c | 62 > ++++++++++++++++++++++++++++++++++++++++++++---- > 1 file changed, 58 insertions(+), 4 deletions(-) > > diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c > index 3fd1d9a..f74ec83 100644 > --- a/arch/powerpc/xmon/xmon.c > +++ b/arch/powerpc/xmon/xmon.c > @@ -48,6 +48,7 @@ > #ifdef CONFIG_PPC64 > #include <asm/hvcall.h> > #include <asm/paca.h> > +#include <asm/plpar_wrappers.h> > #endif > > #include "nonstdio.h" > @@ -89,6 +90,7 @@ struct bpt { > /* Bits in bpt.enabled */ > #define BP_IABR_TE 1 /* IABR translation enabled */ > #define BP_IABR 2 > +#define BP_CIABR 4 > #define BP_TRAP 8 > #define BP_DABR 0x10 > > @@ -97,6 +99,7 @@ static struct bpt bpts[NBPTS]; > static struct bpt dabr; > static struct bpt *iabr; > static unsigned bpinstr = 0x7fe00008; /* trap */ > +static bool ciabr_used = false; /* CIABR instruction breakpoint > */ > > #define BP_NUM(bp) ((bp) - bpts + 1) > > @@ -269,6 +272,34 @@ static inline void cinval(void *p) > asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p)); > } > > +static void write_ciabr(unsigned long ciabr) > +{ > + if (cpu_has_feature(CPU_FTR_HVMODE)) { > + mtspr(SPRN_CIABR, ciabr); > + return; > + } > + > +#ifdef CONFIG_PPC64 > + plapr_set_ciabr(ciabr); > +#endif > +} > + > +static void set_ciabr(unsigned long addr) > +{ > + addr &= ~CIABR_PRIV; > + if (cpu_has_feature(CPU_FTR_HVMODE)) > + addr |= CIABR_PRIV_HYPER; > + else > + addr |= CIABR_PRIV_SUPER; > + write_ciabr(addr); > +} > + > +static void clear_ciabr(void) > +{ > + if (cpu_has_feature(CPU_FTR_ARCH_207S)) > + write_ciabr(0); > +} > + > /* > * Disable surveillance (the service processor watchdog function) > * while we are in xmon. > @@ -764,6 +795,9 @@ static void insert_cpu_bpts(void) > if (iabr && cpu_has_feature(CPU_FTR_IABR)) > mtspr(SPRN_IABR, iabr->address > | (iabr->enabled & (BP_IABR|BP_IABR_TE))); > + > + if (iabr && cpu_has_feature(CPU_FTR_ARCH_207S)) > + set_ciabr(iabr->address); > } > > static void remove_bpts(void) > @@ -791,6 +825,7 @@ static void remove_cpu_bpts(void) > hw_breakpoint_disable(); > if (cpu_has_feature(CPU_FTR_IABR)) > mtspr(SPRN_IABR, 0); > + clear_ciabr(); > } > > /* Command interpreting routine */ > @@ -1124,7 +1159,7 @@ static char *breakpoint_help_string = > "b <addr> [cnt] set breakpoint at given instr addr\n" > "bc clear all breakpoints\n" > "bc <n/addr> clear breakpoint number n or at addr\n" > - "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n" > + "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64/POWER8 > only)\n" > "bd <addr> [cnt] set hardware data breakpoint\n" > ""; > > @@ -1163,11 +1198,20 @@ bpt_cmds(void) > break; > > case 'i': /* bi - hardware instr breakpoint */ > - if (!cpu_has_feature(CPU_FTR_IABR)) { > + if (!cpu_has_feature(CPU_FTR_IABR) && > !cpu_has_feature(CPU_FTR_ARCH_207S)) { > printf("Hardware instruction breakpoint " > "not supported on this cpu\n"); > break; > } > + > + if (cpu_has_feature(CPU_FTR_ARCH_207S)) { > + if (ciabr_used) { > + printf("One instruction breakpoint " > + "possible with CIABR\n"); > + break; > + }
We don't seem to do that with iabr ? Why keep ciabr different > + } Why is this implemented different than existing iabr, You could do this with iabr and iabr->enabled = BP_CIABR right ? > + > if (iabr) { > iabr->enabled &= ~(BP_IABR | BP_IABR_TE); > iabr = NULL; > @@ -1178,7 +1222,12 @@ bpt_cmds(void) > break; > bp = new_breakpoint(a); > if (bp != NULL) { > - bp->enabled |= BP_IABR | BP_IABR_TE; > + if (cpu_has_feature(CPU_FTR_ARCH_207S)) { > + bp->enabled |= BP_CIABR; > + ciabr_used = true; > + } > + else > + bp->enabled |= BP_IABR | BP_IABR_TE; > iabr = bp; > } -aneesh _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev