aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnshuman Khandual <khandual@linux.vnet.ibm.com>2014-11-27 23:36:42 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2014-12-01 22:23:04 -0500
commit1ad7d70562eeb14df8b6d3e1a0a56f1bdfb990f7 (patch)
tree35c8d05d77552e4baf4abce3dd345da946d3cc66
parentb5be75d00833a3f0ff76b1d7473119be33367faa (diff)
powerpc/xmon: Enable HW instruction breakpoint on POWER8
This patch enables support for hardware instruction breakpoint in xmon on POWER8 platform with the help of a new register called the CIABR (Completed Instruction Address Breakpoint Register). With this patch, a single hardware instruction breakpoint can be added and cleared during any active xmon debug session. The hardware based instruction breakpoint mechanism works correctly with the existing TRAP based instruction breakpoint available on xmon. There are no powerpc CPU with CPU_FTR_IABR feature any more. This patch has re-purposed all the existing IABR related code to work with CIABR register based HW instruction breakpoint. This has one odd feature, which is that when we hit a breakpoint xmon doesn't tell us we have hit the breakpoint. This is because xmon is expecting bp->address == regs->nip. Because CIABR fires on completition regs->nip points to the instruction after the breakpoint. We could fix that, but it would then confuse other parts of the xmon code which think we need to emulate the instruction. [mpe] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
-rw-r--r--arch/powerpc/xmon/xmon.c58
1 files changed, 51 insertions, 7 deletions
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index ef18021d52e1..820dc135f040 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -51,6 +51,12 @@
51#include <asm/paca.h> 51#include <asm/paca.h>
52#endif 52#endif
53 53
54#if defined(CONFIG_PPC_SPLPAR)
55#include <asm/plpar_wrappers.h>
56#else
57static inline long plapr_set_ciabr(unsigned long ciabr) {return 0; };
58#endif
59
54#include "nonstdio.h" 60#include "nonstdio.h"
55#include "dis-asm.h" 61#include "dis-asm.h"
56 62
@@ -270,6 +276,45 @@ static inline void cinval(void *p)
270 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p)); 276 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
271} 277}
272 278
279/**
280 * write_ciabr() - write the CIABR SPR
281 * @ciabr: The value to write.
282 *
283 * This function writes a value to the CIARB register either directly
284 * through mtspr instruction if the kernel is in HV privilege mode or
285 * call a hypervisor function to achieve the same in case the kernel
286 * is in supervisor privilege mode.
287 */
288static void write_ciabr(unsigned long ciabr)
289{
290 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
291 return;
292
293 if (cpu_has_feature(CPU_FTR_HVMODE)) {
294 mtspr(SPRN_CIABR, ciabr);
295 return;
296 }
297 plapr_set_ciabr(ciabr);
298}
299
300/**
301 * set_ciabr() - set the CIABR
302 * @addr: The value to set.
303 *
304 * This function sets the correct privilege value into the the HW
305 * breakpoint address before writing it up in the CIABR register.
306 */
307static void set_ciabr(unsigned long addr)
308{
309 addr &= ~CIABR_PRIV;
310
311 if (cpu_has_feature(CPU_FTR_HVMODE))
312 addr |= CIABR_PRIV_HYPER;
313 else
314 addr |= CIABR_PRIV_SUPER;
315 write_ciabr(addr);
316}
317
273/* 318/*
274 * Disable surveillance (the service processor watchdog function) 319 * Disable surveillance (the service processor watchdog function)
275 * while we are in xmon. 320 * while we are in xmon.
@@ -764,9 +809,9 @@ static void insert_cpu_bpts(void)
764 brk.len = 8; 809 brk.len = 8;
765 __set_breakpoint(&brk); 810 __set_breakpoint(&brk);
766 } 811 }
767 if (iabr && cpu_has_feature(CPU_FTR_IABR)) 812
768 mtspr(SPRN_IABR, iabr->address 813 if (iabr)
769 | (iabr->enabled & (BP_IABR|BP_IABR_TE))); 814 set_ciabr(iabr->address);
770} 815}
771 816
772static void remove_bpts(void) 817static void remove_bpts(void)
@@ -792,8 +837,7 @@ static void remove_bpts(void)
792static void remove_cpu_bpts(void) 837static void remove_cpu_bpts(void)
793{ 838{
794 hw_breakpoint_disable(); 839 hw_breakpoint_disable();
795 if (cpu_has_feature(CPU_FTR_IABR)) 840 write_ciabr(0);
796 mtspr(SPRN_IABR, 0);
797} 841}
798 842
799/* Command interpreting routine */ 843/* Command interpreting routine */
@@ -1128,7 +1172,7 @@ static char *breakpoint_help_string =
1128 "b <addr> [cnt] set breakpoint at given instr addr\n" 1172 "b <addr> [cnt] set breakpoint at given instr addr\n"
1129 "bc clear all breakpoints\n" 1173 "bc clear all breakpoints\n"
1130 "bc <n/addr> clear breakpoint number n or at addr\n" 1174 "bc <n/addr> clear breakpoint number n or at addr\n"
1131 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n" 1175 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
1132 "bd <addr> [cnt] set hardware data breakpoint\n" 1176 "bd <addr> [cnt] set hardware data breakpoint\n"
1133 ""; 1177 "";
1134 1178
@@ -1167,7 +1211,7 @@ bpt_cmds(void)
1167 break; 1211 break;
1168 1212
1169 case 'i': /* bi - hardware instr breakpoint */ 1213 case 'i': /* bi - hardware instr breakpoint */
1170 if (!cpu_has_feature(CPU_FTR_IABR)) { 1214 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
1171 printf("Hardware instruction breakpoint " 1215 printf("Hardware instruction breakpoint "
1172 "not supported on this cpu\n"); 1216 "not supported on this cpu\n");
1173 break; 1217 break;