[PATCH] powerpc, xmon: Enable hardware instruction breakpoint support on POWER8
Anshuman Khandual
khandual at linux.vnet.ibm.com
Thu Jun 12 18:19:20 EST 2014
On 06/04/2014 02:18 PM, Anshuman Khandual wrote:
> On 06/03/2014 11:33 AM, Anshuman Khandual wrote:
>> On 05/30/2014 07:12 PM, Aneesh Kumar K.V wrote:
>>>> 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
>
>> Right now with the IABR implementation if we try to set hardware instruction
>> breakpoint while one is already there, it just get overridden with the new
>> address without complaining. I thought with this at least for CIABR cases,
>> it will complain about it and require the user to clear the breakpoint
>> explicitly before allowing a new breakpoint. Okay will remove this.
>>
>
> I tried removing the "ciabr_used" variable and all related checks/assignments on it.
> Then I was able to add all these three address as hardware instruction breakpoint
> and xmon never complained that it might override the existing actual checkpoint
> implemented with CIABR. It accepted all the three addresses which can later be
> listed as below.
>
> 0:mon> b
> type address
> 1 inst c0000000000830d0 .power_pmu_add+0x0/0x2e0
> 2 inst c000000000084690 .power_pmu_del+0x0/0x3a0
> 3 inst c000000000085060 .perf_event_interrupt+0x0/0x480
>
> But in reality, only perf_event_interrupt function's address got written into CIABR
> register and got triggered with the workload. I dont have a system which has IABR
> support to test it's behaviour for this situation. But this does not sound okay,
> we should explicitly inform the user that the hardware instruction breakpoint has
> been overridden with the latest command or reject the attempt. Looking for some
> suggestions in this regard. Thank you.
Hey Ben/MPE,
Any suggestions on this ^^^^^^^^^^^^ ?
More information about the Linuxppc-dev
mailing list