[PATCH] powerpc, xmon: Enable hardware instruction breakpoint support on POWER8
Aneesh Kumar K.V
aneesh.kumar at linux.vnet.ibm.com
Fri May 30 23:42:14 EST 2014
Anshuman Khandual <khandual at 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 <khandual at 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
More information about the Linuxppc-dev
mailing list