aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Leroy <christophe.leroy@c-s.fr>2016-11-29 03:52:15 -0500
committerScott Wood <oss@buserror.net>2017-01-25 03:43:59 -0500
commit4ad8622dc54895c0072ddc919a83ea2a2f05605f (patch)
treee8e12d018aef8f30dd591f8963b72773a9e5f1c9
parentfa769d3f58e6b0db4ed9f5f05ef1f251692f90c6 (diff)
powerpc/8xx: Implement hw_breakpoint
This patch implements HW breakpoint on the 8xx. The 8xx has capability to manage HW breakpoints, which is slightly different than BOOK3S: 1/ The breakpoint match doesn't trigger a DSI exception but a dedicated data breakpoint exception. 2/ The breakpoint happens after the instruction has completed, no need to single step or emulate the instruction, 3/ Matched address is not set in DAR but in BAR, 4/ DABR register doesn't exist, instead we have registers LCTRL1, LCTRL2 and CMPx registers, 5/ The match on one comparator is not on a double word but on a single word. The patch does: 1/ Prepare the dedicated registers in call to __set_dabr(). In order to emulate the double word handling of BOOK3S, comparator E is set to DABR address value and comparator F to address + 4. Then breakpoint 1 is set to match comparator E or F, 2/ Skip the singlestepping stage when compiled for CONFIG_PPC_8xx, 3/ Implement the exception. In that exception, the matched address is taken from SPRN_BAR and manage as if it was from SPRN_DAR. 4/ I/D TLB error exception routines perform a tlbie on bad TLBs. That tlbie triggers the breakpoint exception when performed on the breakpoint address. For this reason, the routine returns if the match is from one of those two tlbie. Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> Signed-off-by: Scott Wood <oss@buserror.net>
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--arch/powerpc/include/asm/reg_8xx.h7
-rw-r--r--arch/powerpc/kernel/head_8xx.S28
-rw-r--r--arch/powerpc/kernel/hw_breakpoint.c6
-rw-r--r--arch/powerpc/kernel/process.c22
5 files changed, 62 insertions, 3 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 1971ed4e0336..8b201eefdeaa 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -113,7 +113,7 @@ config PPC
113 select HAVE_PERF_REGS 113 select HAVE_PERF_REGS
114 select HAVE_PERF_USER_STACK_DUMP 114 select HAVE_PERF_USER_STACK_DUMP
115 select HAVE_REGS_AND_STACK_ACCESS_API 115 select HAVE_REGS_AND_STACK_ACCESS_API
116 select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S 116 select HAVE_HW_BREAKPOINT if PERF_EVENTS && (PPC_BOOK3S || PPC_8xx)
117 select ARCH_WANT_IPC_PARSE_VERSION 117 select ARCH_WANT_IPC_PARSE_VERSION
118 select SPARSE_IRQ 118 select SPARSE_IRQ
119 select IRQ_DOMAIN 119 select IRQ_DOMAIN
diff --git a/arch/powerpc/include/asm/reg_8xx.h b/arch/powerpc/include/asm/reg_8xx.h
index 1f1636124a04..c52725b7085d 100644
--- a/arch/powerpc/include/asm/reg_8xx.h
+++ b/arch/powerpc/include/asm/reg_8xx.h
@@ -29,6 +29,13 @@
29#define SPRN_EIE 80 /* External interrupt enable (EE=1, RI=1) */ 29#define SPRN_EIE 80 /* External interrupt enable (EE=1, RI=1) */
30#define SPRN_EID 81 /* External interrupt disable (EE=0, RI=1) */ 30#define SPRN_EID 81 /* External interrupt disable (EE=0, RI=1) */
31 31
32/* Debug registers */
33#define SPRN_CMPE 152
34#define SPRN_CMPF 153
35#define SPRN_LCTRL1 156
36#define SPRN_LCTRL2 157
37#define SPRN_BAR 159
38
32/* Commands. Only the first few are available to the instruction cache. 39/* Commands. Only the first few are available to the instruction cache.
33*/ 40*/
34#define IDC_ENABLE 0x02000000 /* Cache enable */ 41#define IDC_ENABLE 0x02000000 /* Cache enable */
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 1a9c99d3e5d8..5fcbd79a121d 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -561,6 +561,7 @@ InstructionTLBError:
561 andis. r10,r5,0x4000 561 andis. r10,r5,0x4000
562 beq+ 1f 562 beq+ 1f
563 tlbie r4 563 tlbie r4
564itlbie:
564 /* 0x400 is InstructionAccess exception, needed by bad_page_fault() */ 565 /* 0x400 is InstructionAccess exception, needed by bad_page_fault() */
5651: EXC_XFER_LITE(0x400, handle_page_fault) 5661: EXC_XFER_LITE(0x400, handle_page_fault)
566 567
@@ -585,6 +586,7 @@ DARFixed:/* Return from dcbx instruction bug workaround */
585 andis. r10,r5,0x4000 586 andis. r10,r5,0x4000
586 beq+ 1f 587 beq+ 1f
587 tlbie r4 588 tlbie r4
589dtlbie:
5881: li r10,RPN_PATTERN 5901: li r10,RPN_PATTERN
589 mtspr SPRN_DAR,r10 /* Tag DAR, to be used in DTLB Error */ 591 mtspr SPRN_DAR,r10 /* Tag DAR, to be used in DTLB Error */
590 /* 0x300 is DataAccess exception, needed by bad_page_fault() */ 592 /* 0x300 is DataAccess exception, needed by bad_page_fault() */
@@ -602,7 +604,27 @@ DARFixed:/* Return from dcbx instruction bug workaround */
602 * support of breakpoints and such. Someday I will get around to 604 * support of breakpoints and such. Someday I will get around to
603 * using them. 605 * using them.
604 */ 606 */
605 EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_EE) 607 . = 0x1c00
608DataBreakpoint:
609 EXCEPTION_PROLOG_0
610 mfcr r10
611 mfspr r11, SPRN_SRR0
612 cmplwi cr0, r11, (dtlbie - PAGE_OFFSET)@l
613 cmplwi cr7, r11, (itlbie - PAGE_OFFSET)@l
614 beq- cr0, 11f
615 beq- cr7, 11f
616 EXCEPTION_PROLOG_1
617 EXCEPTION_PROLOG_2
618 addi r3,r1,STACK_FRAME_OVERHEAD
619 mfspr r4,SPRN_BAR
620 stw r4,_DAR(r11)
621 mfspr r5,SPRN_DSISR
622 EXC_XFER_EE(0x1c00, do_break)
62311:
624 mtcr r10
625 EXCEPTION_EPILOG_0
626 rfi
627
606 EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_EE) 628 EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_EE)
607 EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_EE) 629 EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_EE)
608 EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_EE) 630 EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_EE)
@@ -977,6 +999,10 @@ initial_mmu:
977 lis r8, IDC_ENABLE@h 999 lis r8, IDC_ENABLE@h
978 mtspr SPRN_DC_CST, r8 1000 mtspr SPRN_DC_CST, r8
979#endif 1001#endif
1002 /* Disable debug mode entry on data breakpoints */
1003 mfspr r8, SPRN_DER
1004 rlwinm r8, r8, 0, ~0x8
1005 mtspr SPRN_DER, r8
980 blr 1006 blr
981 1007
982 1008
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index 4d3aa05e28be..146eaa9b350e 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -211,9 +211,11 @@ int hw_breakpoint_handler(struct die_args *args)
211 int rc = NOTIFY_STOP; 211 int rc = NOTIFY_STOP;
212 struct perf_event *bp; 212 struct perf_event *bp;
213 struct pt_regs *regs = args->regs; 213 struct pt_regs *regs = args->regs;
214#ifndef CONFIG_PPC_8xx
214 int stepped = 1; 215 int stepped = 1;
215 struct arch_hw_breakpoint *info;
216 unsigned int instr; 216 unsigned int instr;
217#endif
218 struct arch_hw_breakpoint *info;
217 unsigned long dar = regs->dar; 219 unsigned long dar = regs->dar;
218 220
219 /* Disable breakpoints during exception handling */ 221 /* Disable breakpoints during exception handling */
@@ -255,6 +257,7 @@ int hw_breakpoint_handler(struct die_args *args)
255 (dar - bp->attr.bp_addr < bp->attr.bp_len))) 257 (dar - bp->attr.bp_addr < bp->attr.bp_len)))
256 info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ; 258 info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
257 259
260#ifndef CONFIG_PPC_8xx
258 /* Do not emulate user-space instructions, instead single-step them */ 261 /* Do not emulate user-space instructions, instead single-step them */
259 if (user_mode(regs)) { 262 if (user_mode(regs)) {
260 current->thread.last_hit_ubp = bp; 263 current->thread.last_hit_ubp = bp;
@@ -278,6 +281,7 @@ int hw_breakpoint_handler(struct die_args *args)
278 perf_event_disable_inatomic(bp); 281 perf_event_disable_inatomic(bp);
279 goto out; 282 goto out;
280 } 283 }
284#endif
281 /* 285 /*
282 * As a policy, the callback is invoked in a 'trigger-after-execute' 286 * As a policy, the callback is invoked in a 'trigger-after-execute'
283 * fashion 287 * fashion
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 04885cec24df..2dcb65fee638 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -736,6 +736,28 @@ static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
736 mtspr(SPRN_DABRX, dabrx); 736 mtspr(SPRN_DABRX, dabrx);
737 return 0; 737 return 0;
738} 738}
739#elif defined(CONFIG_PPC_8xx)
740static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
741{
742 unsigned long addr = dabr & ~HW_BRK_TYPE_DABR;
743 unsigned long lctrl1 = 0x90000000; /* compare type: equal on E & F */
744 unsigned long lctrl2 = 0x8e000002; /* watchpoint 1 on cmp E | F */
745
746 if ((dabr & HW_BRK_TYPE_RDWR) == HW_BRK_TYPE_READ)
747 lctrl1 |= 0xa0000;
748 else if ((dabr & HW_BRK_TYPE_RDWR) == HW_BRK_TYPE_WRITE)
749 lctrl1 |= 0xf0000;
750 else if ((dabr & HW_BRK_TYPE_RDWR) == 0)
751 lctrl2 = 0;
752
753 mtspr(SPRN_LCTRL2, 0);
754 mtspr(SPRN_CMPE, addr);
755 mtspr(SPRN_CMPF, addr + 4);
756 mtspr(SPRN_LCTRL1, lctrl1);
757 mtspr(SPRN_LCTRL2, lctrl2);
758
759 return 0;
760}
739#else 761#else
740static inline int __set_dabr(unsigned long dabr, unsigned long dabrx) 762static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
741{ 763{