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>
This commit is contained in:
Christophe Leroy 2016-11-29 09:52:15 +01:00 committed by Scott Wood
parent fa769d3f58
commit 4ad8622dc5
5 changed files with 62 additions and 3 deletions

View File

@ -113,7 +113,7 @@ config PPC
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S
select HAVE_HW_BREAKPOINT if PERF_EVENTS && (PPC_BOOK3S || PPC_8xx)
select ARCH_WANT_IPC_PARSE_VERSION
select SPARSE_IRQ
select IRQ_DOMAIN

View File

@ -29,6 +29,13 @@
#define SPRN_EIE 80 /* External interrupt enable (EE=1, RI=1) */
#define SPRN_EID 81 /* External interrupt disable (EE=0, RI=1) */
/* Debug registers */
#define SPRN_CMPE 152
#define SPRN_CMPF 153
#define SPRN_LCTRL1 156
#define SPRN_LCTRL2 157
#define SPRN_BAR 159
/* Commands. Only the first few are available to the instruction cache.
*/
#define IDC_ENABLE 0x02000000 /* Cache enable */

View File

@ -561,6 +561,7 @@ InstructionTLBError:
andis. r10,r5,0x4000
beq+ 1f
tlbie r4
itlbie:
/* 0x400 is InstructionAccess exception, needed by bad_page_fault() */
1: EXC_XFER_LITE(0x400, handle_page_fault)
@ -585,6 +586,7 @@ DARFixed:/* Return from dcbx instruction bug workaround */
andis. r10,r5,0x4000
beq+ 1f
tlbie r4
dtlbie:
1: li r10,RPN_PATTERN
mtspr SPRN_DAR,r10 /* Tag DAR, to be used in DTLB Error */
/* 0x300 is DataAccess exception, needed by bad_page_fault() */
@ -602,7 +604,27 @@ DARFixed:/* Return from dcbx instruction bug workaround */
* support of breakpoints and such. Someday I will get around to
* using them.
*/
EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_EE)
. = 0x1c00
DataBreakpoint:
EXCEPTION_PROLOG_0
mfcr r10
mfspr r11, SPRN_SRR0
cmplwi cr0, r11, (dtlbie - PAGE_OFFSET)@l
cmplwi cr7, r11, (itlbie - PAGE_OFFSET)@l
beq- cr0, 11f
beq- cr7, 11f
EXCEPTION_PROLOG_1
EXCEPTION_PROLOG_2
addi r3,r1,STACK_FRAME_OVERHEAD
mfspr r4,SPRN_BAR
stw r4,_DAR(r11)
mfspr r5,SPRN_DSISR
EXC_XFER_EE(0x1c00, do_break)
11:
mtcr r10
EXCEPTION_EPILOG_0
rfi
EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_EE)
EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_EE)
EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_EE)
@ -977,6 +999,10 @@ initial_mmu:
lis r8, IDC_ENABLE@h
mtspr SPRN_DC_CST, r8
#endif
/* Disable debug mode entry on data breakpoints */
mfspr r8, SPRN_DER
rlwinm r8, r8, 0, ~0x8
mtspr SPRN_DER, r8
blr

View File

@ -211,9 +211,11 @@ int hw_breakpoint_handler(struct die_args *args)
int rc = NOTIFY_STOP;
struct perf_event *bp;
struct pt_regs *regs = args->regs;
#ifndef CONFIG_PPC_8xx
int stepped = 1;
struct arch_hw_breakpoint *info;
unsigned int instr;
#endif
struct arch_hw_breakpoint *info;
unsigned long dar = regs->dar;
/* Disable breakpoints during exception handling */
@ -255,6 +257,7 @@ int hw_breakpoint_handler(struct die_args *args)
(dar - bp->attr.bp_addr < bp->attr.bp_len)))
info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
#ifndef CONFIG_PPC_8xx
/* Do not emulate user-space instructions, instead single-step them */
if (user_mode(regs)) {
current->thread.last_hit_ubp = bp;
@ -278,6 +281,7 @@ int hw_breakpoint_handler(struct die_args *args)
perf_event_disable_inatomic(bp);
goto out;
}
#endif
/*
* As a policy, the callback is invoked in a 'trigger-after-execute'
* fashion

View File

@ -736,6 +736,28 @@ static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
mtspr(SPRN_DABRX, dabrx);
return 0;
}
#elif defined(CONFIG_PPC_8xx)
static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
{
unsigned long addr = dabr & ~HW_BRK_TYPE_DABR;
unsigned long lctrl1 = 0x90000000; /* compare type: equal on E & F */
unsigned long lctrl2 = 0x8e000002; /* watchpoint 1 on cmp E | F */
if ((dabr & HW_BRK_TYPE_RDWR) == HW_BRK_TYPE_READ)
lctrl1 |= 0xa0000;
else if ((dabr & HW_BRK_TYPE_RDWR) == HW_BRK_TYPE_WRITE)
lctrl1 |= 0xf0000;
else if ((dabr & HW_BRK_TYPE_RDWR) == 0)
lctrl2 = 0;
mtspr(SPRN_LCTRL2, 0);
mtspr(SPRN_CMPE, addr);
mtspr(SPRN_CMPF, addr + 4);
mtspr(SPRN_LCTRL1, lctrl1);
mtspr(SPRN_LCTRL2, lctrl2);
return 0;
}
#else
static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
{