Commit 1ad7d705 authored by Anshuman Khandual's avatar Anshuman Khandual Committed by Michael Ellerman

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: default avatarMichael Ellerman <mpe@ellerman.id.au>
Signed-off-by: default avatarAnshuman Khandual <khandual@linux.vnet.ibm.com>
parent b5be75d0
...@@ -51,6 +51,12 @@ ...@@ -51,6 +51,12 @@
#include <asm/paca.h> #include <asm/paca.h>
#endif #endif
#if defined(CONFIG_PPC_SPLPAR)
#include <asm/plpar_wrappers.h>
#else
static inline long plapr_set_ciabr(unsigned long ciabr) {return 0; };
#endif
#include "nonstdio.h" #include "nonstdio.h"
#include "dis-asm.h" #include "dis-asm.h"
...@@ -270,6 +276,45 @@ static inline void cinval(void *p) ...@@ -270,6 +276,45 @@ static inline void cinval(void *p)
asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p)); asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
} }
/**
* write_ciabr() - write the CIABR SPR
* @ciabr: The value to write.
*
* This function writes a value to the CIARB register either directly
* through mtspr instruction if the kernel is in HV privilege mode or
* call a hypervisor function to achieve the same in case the kernel
* is in supervisor privilege mode.
*/
static void write_ciabr(unsigned long ciabr)
{
if (!cpu_has_feature(CPU_FTR_ARCH_207S))
return;
if (cpu_has_feature(CPU_FTR_HVMODE)) {
mtspr(SPRN_CIABR, ciabr);
return;
}
plapr_set_ciabr(ciabr);
}
/**
* set_ciabr() - set the CIABR
* @addr: The value to set.
*
* This function sets the correct privilege value into the the HW
* breakpoint address before writing it up in the CIABR register.
*/
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);
}
/* /*
* Disable surveillance (the service processor watchdog function) * Disable surveillance (the service processor watchdog function)
* while we are in xmon. * while we are in xmon.
...@@ -764,9 +809,9 @@ static void insert_cpu_bpts(void) ...@@ -764,9 +809,9 @@ static void insert_cpu_bpts(void)
brk.len = 8; brk.len = 8;
__set_breakpoint(&brk); __set_breakpoint(&brk);
} }
if (iabr && cpu_has_feature(CPU_FTR_IABR))
mtspr(SPRN_IABR, iabr->address if (iabr)
| (iabr->enabled & (BP_IABR|BP_IABR_TE))); set_ciabr(iabr->address);
} }
static void remove_bpts(void) static void remove_bpts(void)
...@@ -792,8 +837,7 @@ static void remove_bpts(void) ...@@ -792,8 +837,7 @@ static void remove_bpts(void)
static void remove_cpu_bpts(void) static void remove_cpu_bpts(void)
{ {
hw_breakpoint_disable(); hw_breakpoint_disable();
if (cpu_has_feature(CPU_FTR_IABR)) write_ciabr(0);
mtspr(SPRN_IABR, 0);
} }
/* Command interpreting routine */ /* Command interpreting routine */
...@@ -1128,7 +1172,7 @@ static char *breakpoint_help_string = ...@@ -1128,7 +1172,7 @@ static char *breakpoint_help_string =
"b <addr> [cnt] set breakpoint at given instr addr\n" "b <addr> [cnt] set breakpoint at given instr addr\n"
"bc clear all breakpoints\n" "bc clear all breakpoints\n"
"bc <n/addr> clear breakpoint number n or at addr\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 (POWER8 only)\n"
"bd <addr> [cnt] set hardware data breakpoint\n" "bd <addr> [cnt] set hardware data breakpoint\n"
""; "";
...@@ -1167,7 +1211,7 @@ bpt_cmds(void) ...@@ -1167,7 +1211,7 @@ bpt_cmds(void)
break; break;
case 'i': /* bi - hardware instr breakpoint */ case 'i': /* bi - hardware instr breakpoint */
if (!cpu_has_feature(CPU_FTR_IABR)) { if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
printf("Hardware instruction breakpoint " printf("Hardware instruction breakpoint "
"not supported on this cpu\n"); "not supported on this cpu\n");
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment