Commit 7f82e010 authored by Matt Porter's avatar Matt Porter Committed by Linus Torvalds

[PATCH] ppc32: 40x and Book E debug: core support

This patch updates the 40x and Book E Debug exception handling paths to
handle kernel space debug events.  It also fixes up the in-kernel ppc32
kgdb stub to work properly.
Signed-off-by: default avatarMatt Porter <mporter@kernel.crashing.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent bad9a5ae
...@@ -599,64 +599,8 @@ interrupt_base: ...@@ -599,64 +599,8 @@ interrupt_base:
mfspr r10, SPRG0 mfspr r10, SPRG0
b InstructionStorage b InstructionStorage
/* Check for a single step debug exception while in an exception
* handler before state has been saved. This is to catch the case
* where an instruction that we are trying to single step causes
* an exception (eg ITLB/DTLB miss) and thus the first instruction of
* the exception handler generates a single step debug exception.
*
* If we get a debug trap on the first instruction of an exception handler,
* we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
* a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
* The exception handler was handling a non-critical interrupt, so it will
* save (and later restore) the MSR via SPRN_SRR1, which will still have
* the MSR_DE bit set.
*/
/* Debug Interrupt */ /* Debug Interrupt */
START_EXCEPTION(Debug) DEBUG_EXCEPTION
CRITICAL_EXCEPTION_PROLOG
/*
* If this is a single step or branch-taken exception in an
* exception entry sequence, it was probably meant to apply to
* the code where the exception occurred (since exception entry
* doesn't turn off DE automatically). We simulate the effect
* of turning off DE on entry to an exception handler by turning
* off DE in the CSRR1 value and clearing the debug status.
*/
mfspr r10,SPRN_DBSR /* check single-step/branch taken */
andis. r10,r10,(DBSR_IC|DBSR_BT)@h
beq+ 1f
andi. r0,r9,MSR_PR /* check supervisor */
beq 2f /* branch if we need to fix it up... */
/* continue normal handling for a critical exception... */
1: mfspr r4,SPRN_DBSR
addi r3,r1,STACK_FRAME_OVERHEAD
EXC_XFER_TEMPLATE(DebugException, 0x2002, \
(MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
/* here it looks like we got an inappropriate debug exception. */
2: rlwinm r9,r9,0,~MSR_DE /* clear DE in the CSRR1 value */
mtspr SPRN_DBSR,r10 /* clear the IC/BT debug intr status */
/* restore state and get out */
lwz r10,_CCR(r11)
lwz r0,GPR0(r11)
lwz r1,GPR1(r11)
mtcrf 0x80,r10
mtspr CSRR0,r12
mtspr CSRR1,r9
lwz r9,GPR9(r11)
mtspr SPRG2,r8; /* SPRG2 only used in criticals */
lis r8,crit_save@ha;
lwz r10,crit_r10@l(r8)
lwz r11,crit_r11@l(r8)
mfspr r8,SPRG2
rfci
b .
/* /*
* Local functions * Local functions
......
...@@ -709,8 +709,20 @@ label: ...@@ -709,8 +709,20 @@ label:
EXCEPTION(0x1E00, Trap_1E, UnknownException, EXC_XFER_EE) EXCEPTION(0x1E00, Trap_1E, UnknownException, EXC_XFER_EE)
EXCEPTION(0x1F00, Trap_1F, UnknownException, EXC_XFER_EE) EXCEPTION(0x1F00, Trap_1F, UnknownException, EXC_XFER_EE)
/* 0x2000 - Debug Exception /* Check for a single step debug exception while in an exception
*/ * handler before state has been saved. This is to catch the case
* where an instruction that we are trying to single step causes
* an exception (eg ITLB/DTLB miss) and thus the first instruction of
* the exception handler generates a single step debug exception.
*
* If we get a debug trap on the first instruction of an exception handler,
* we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
* a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
* The exception handler was handling a non-critical interrupt, so it will
* save (and later restore) the MSR via SPRN_SRR1, which will still have
* the MSR_DE bit set.
*/
/* 0x2000 - Debug Exception */
START_EXCEPTION(0x2000, DebugTrap) START_EXCEPTION(0x2000, DebugTrap)
CRITICAL_EXCEPTION_PROLOG CRITICAL_EXCEPTION_PROLOG
...@@ -723,21 +735,20 @@ label: ...@@ -723,21 +735,20 @@ label:
* off DE in the SRR3 value and clearing the debug status. * off DE in the SRR3 value and clearing the debug status.
*/ */
mfspr r10,SPRN_DBSR /* check single-step/branch taken */ mfspr r10,SPRN_DBSR /* check single-step/branch taken */
andis. r10,r10,(DBSR_IC|DBSR_BT)@h andis. r10,r10,DBSR_IC@h
beq+ 1f beq+ 2f
andi. r0,r9,MSR_IR|MSR_PR /* check supervisor + MMU off */
beq 2f /* branch if we need to fix it up... */
/* continue normal handling for a critical exception... */ andi. r10,r9,MSR_IR|MSR_PR /* check supervisor + MMU off */
1: mfspr r4,SPRN_DBSR beq 1f /* branch and fix it up */
addi r3,r1,STACK_FRAME_OVERHEAD
EXC_XFER_TEMPLATE(DebugException, 0x2002, \ mfspr r10,SPRN_SRR2 /* Faulting instruction address */
(MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ cmplwi r10,0x2100
NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) bgt+ 2f /* address above exception vectors */
/* here it looks like we got an inappropriate debug exception. */ /* here it looks like we got an inappropriate debug exception. */
2: rlwinm r9,r9,0,~MSR_DE /* clear DE in the SRR3 value */ 1: rlwinm r9,r9,0,~MSR_DE /* clear DE in the SRR3 value */
mtspr SPRN_DBSR,r10 /* clear the IC/BT debug intr status */ lis r10,DBSR_IC@h /* clear the IC event */
mtspr SPRN_DBSR,r10
/* restore state and get out */ /* restore state and get out */
lwz r10,_CCR(r11) lwz r10,_CCR(r11)
lwz r0,GPR0(r11) lwz r0,GPR0(r11)
...@@ -753,6 +764,13 @@ label: ...@@ -753,6 +764,13 @@ label:
rfci rfci
b . b .
/* continue normal handling for a critical exception... */
2: mfspr r4,SPRN_DBSR
addi r3,r1,STACK_FRAME_OVERHEAD
EXC_XFER_TEMPLATE(DebugException, 0x2002, \
(MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
/* /*
* The other Data TLB exceptions bail out to this point * The other Data TLB exceptions bail out to this point
* if they can't resolve the lightweight TLB fault. * if they can't resolve the lightweight TLB fault.
......
...@@ -237,4 +237,70 @@ ...@@ -237,4 +237,70 @@
ret_from_except) ret_from_except)
/* Check for a single step debug exception while in an exception
* handler before state has been saved. This is to catch the case
* where an instruction that we are trying to single step causes
* an exception (eg ITLB/DTLB miss) and thus the first instruction of
* the exception handler generates a single step debug exception.
*
* If we get a debug trap on the first instruction of an exception handler,
* we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
* a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
* The exception handler was handling a non-critical interrupt, so it will
* save (and later restore) the MSR via SPRN_CSRR1, which will still have
* the MSR_DE bit set.
*/
#define DEBUG_EXCEPTION \
START_EXCEPTION(Debug); \
CRITICAL_EXCEPTION_PROLOG; \
\
/* \
* If there is a single step or branch-taken exception in an \
* exception entry sequence, it was probably meant to apply to \
* the code where the exception occurred (since exception entry \
* doesn't turn off DE automatically). We simulate the effect \
* of turning off DE on entry to an exception handler by turning \
* off DE in the CSRR1 value and clearing the debug status. \
*/ \
mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \
andis. r10,r10,DBSR_IC@h; \
beq+ 2f; \
\
lis r10,KERNELBASE@h; /* check if exception in vectors */ \
ori r10,r10,KERNELBASE@l; \
cmplw r12,r10; \
blt+ 2f; /* addr below exception vectors */ \
\
lis r10,Debug@h; \
ori r10,r10,Debug@l; \
cmplw r12,r10; \
bgt+ 2f; /* addr above exception vectors */ \
\
/* here it looks like we got an inappropriate debug exception. */ \
1: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CSRR1 value */ \
lis r10,DBSR_IC@h; /* clear the IC event */ \
mtspr SPRN_DBSR,r10; \
/* restore state and get out */ \
lwz r10,_CCR(r11); \
lwz r0,GPR0(r11); \
lwz r1,GPR1(r11); \
mtcrf 0x80,r10; \
mtspr CSRR0,r12; \
mtspr CSRR1,r9; \
lwz r9,GPR9(r11); \
lwz r12,GPR12(r11); \
mtspr SPRG2,r8; /* SPRG2 only used in criticals */ \
lis r8,crit_save@ha; \
lwz r10,crit_r10@l(r8); \
lwz r11,crit_r11@l(r8); \
mfspr r8,SPRG2; \
\
rfci; \
b .; \
\
/* continue normal handling for a critical exception... */ \
2: mfspr r4,SPRN_DBSR; \
addi r3,r1,STACK_FRAME_OVERHEAD; \
EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
#endif /* __HEAD_BOOKE_H__ */ #endif /* __HEAD_BOOKE_H__ */
...@@ -668,64 +668,8 @@ interrupt_base: ...@@ -668,64 +668,8 @@ interrupt_base:
/* Performance Monitor */ /* Performance Monitor */
EXCEPTION(0x2060, PerformanceMonitor, UnknownException, EXC_XFER_EE) EXCEPTION(0x2060, PerformanceMonitor, UnknownException, EXC_XFER_EE)
/* Check for a single step debug exception while in an exception
* handler before state has been saved. This is to catch the case
* where an instruction that we are trying to single step causes
* an exception (eg ITLB/DTLB miss) and thus the first instruction of
* the exception handler generates a single step debug exception.
*
* If we get a debug trap on the first instruction of an exception handler,
* we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
* a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
* The exception handler was handling a non-critical interrupt, so it will
* save (and later restore) the MSR via SPRN_SRR1, which will still have
* the MSR_DE bit set.
*/
/* Debug Interrupt */ /* Debug Interrupt */
START_EXCEPTION(Debug) DEBUG_EXCEPTION
CRITICAL_EXCEPTION_PROLOG
/*
* If this is a single step or branch-taken exception in an
* exception entry sequence, it was probably meant to apply to
* the code where the exception occurred (since exception entry
* doesn't turn off DE automatically). We simulate the effect
* of turning off DE on entry to an exception handler by turning
* off DE in the CSRR1 value and clearing the debug status.
*/
mfspr r10,SPRN_DBSR /* check single-step/branch taken */
andis. r10,r10,(DBSR_IC|DBSR_BT)@h
beq+ 1f
andi. r0,r9,MSR_PR /* check supervisor */
beq 2f /* branch if we need to fix it up... */
/* continue normal handling for a critical exception... */
1: mfspr r4,SPRN_DBSR
addi r3,r1,STACK_FRAME_OVERHEAD
EXC_XFER_TEMPLATE(DebugException, 0x2002, \
(MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
/* here it looks like we got an inappropriate debug exception. */
2: rlwinm r9,r9,0,~MSR_DE /* clear DE in the CSRR1 value */
mtspr SPRN_DBSR,r10 /* clear the IC/BT debug intr status */
/* restore state and get out */
lwz r10,_CCR(r11)
lwz r0,GPR0(r11)
lwz r1,GPR1(r11)
mtcrf 0x80,r10
mtspr CSRR0,r12
mtspr CSRR1,r9
lwz r9,GPR9(r11)
mtspr SPRG2,r8; /* SPRG2 only used in criticals */
lis r8,crit_save@ha;
lwz r10,crit_r10@l(r8)
lwz r11,crit_r11@l(r8)
mfspr r8,SPRG2
rfci
b .
/* /*
* Local functions * Local functions
......
...@@ -498,7 +498,7 @@ static struct hard_trap_info ...@@ -498,7 +498,7 @@ static struct hard_trap_info
unsigned int tt; /* Trap type code for powerpc */ unsigned int tt; /* Trap type code for powerpc */
unsigned char signo; /* Signal that we map this trap into */ unsigned char signo; /* Signal that we map this trap into */
} hard_trap_info[] = { } hard_trap_info[] = {
#if defined(CONFIG_40x) #if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
{ 0x100, SIGINT }, /* critical input interrupt */ { 0x100, SIGINT }, /* critical input interrupt */
{ 0x200, SIGSEGV }, /* machine check */ { 0x200, SIGSEGV }, /* machine check */
{ 0x300, SIGSEGV }, /* data storage */ { 0x300, SIGSEGV }, /* data storage */
...@@ -521,7 +521,7 @@ static struct hard_trap_info ...@@ -521,7 +521,7 @@ static struct hard_trap_info
** 0x1100 data TLB miss ** 0x1100 data TLB miss
** 0x1200 instruction TLB miss ** 0x1200 instruction TLB miss
*/ */
{ 0x2000, SIGTRAP}, /* debug */ { 0x2002, SIGTRAP}, /* debug */
#else #else
{ 0x200, SIGSEGV }, /* machine check */ { 0x200, SIGSEGV }, /* machine check */
{ 0x300, SIGSEGV }, /* address error (store) */ { 0x300, SIGSEGV }, /* address error (store) */
...@@ -602,11 +602,6 @@ handle_exception (struct pt_regs *regs) ...@@ -602,11 +602,6 @@ handle_exception (struct pt_regs *regs)
sigval = computeSignal(regs->trap); sigval = computeSignal(regs->trap);
ptr = remcomOutBuffer; ptr = remcomOutBuffer;
#if defined(CONFIG_40x)
*ptr++ = 'S';
*ptr++ = hexchars[sigval >> 4];
*ptr++ = hexchars[sigval & 0xf];
#else
*ptr++ = 'T'; *ptr++ = 'T';
*ptr++ = hexchars[sigval >> 4]; *ptr++ = hexchars[sigval >> 4];
*ptr++ = hexchars[sigval & 0xf]; *ptr++ = hexchars[sigval & 0xf];
...@@ -620,8 +615,6 @@ handle_exception (struct pt_regs *regs) ...@@ -620,8 +615,6 @@ handle_exception (struct pt_regs *regs)
*ptr++ = ':'; *ptr++ = ':';
ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4); ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4);
*ptr++ = ';'; *ptr++ = ';';
#endif
*ptr++ = 0; *ptr++ = 0;
putpacket(remcomOutBuffer); putpacket(remcomOutBuffer);
...@@ -774,10 +767,6 @@ handle_exception (struct pt_regs *regs) ...@@ -774,10 +767,6 @@ handle_exception (struct pt_regs *regs)
* some location may have changed something that is in the instruction cache. * some location may have changed something that is in the instruction cache.
*/ */
kgdb_flush_cache_all(); kgdb_flush_cache_all();
#if defined(CONFIG_40x)
strcpy(remcomOutBuffer, "OK");
putpacket(remcomOutBuffer);
#endif
mtmsr(msr); mtmsr(msr);
kgdb_interruptible(1); kgdb_interruptible(1);
...@@ -791,10 +780,9 @@ handle_exception (struct pt_regs *regs) ...@@ -791,10 +780,9 @@ handle_exception (struct pt_regs *regs)
case 's': case 's':
kgdb_flush_cache_all(); kgdb_flush_cache_all();
#if defined(CONFIG_40x) #if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC);
regs->msr |= MSR_DE; regs->msr |= MSR_DE;
regs->dbcr0 |= (DBCR0_IDM | DBCR0_IC);
mtmsr(msr);
#else #else
regs->msr |= MSR_SE; regs->msr |= MSR_SE;
#endif #endif
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
/* /*
* Set of msr bits that gdb can change on behalf of a process. * Set of msr bits that gdb can change on behalf of a process.
*/ */
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) #if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
#define MSR_DEBUGCHANGE 0 #define MSR_DEBUGCHANGE 0
#else #else
#define MSR_DEBUGCHANGE (MSR_SE | MSR_BE) #define MSR_DEBUGCHANGE (MSR_SE | MSR_BE)
...@@ -201,9 +201,9 @@ set_single_step(struct task_struct *task) ...@@ -201,9 +201,9 @@ set_single_step(struct task_struct *task)
struct pt_regs *regs = task->thread.regs; struct pt_regs *regs = task->thread.regs;
if (regs != NULL) { if (regs != NULL) {
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) #if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC; task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
/* MSR.DE should already be set */ regs->msr |= MSR_DE;
#else #else
regs->msr |= MSR_SE; regs->msr |= MSR_SE;
#endif #endif
...@@ -216,8 +216,9 @@ clear_single_step(struct task_struct *task) ...@@ -216,8 +216,9 @@ clear_single_step(struct task_struct *task)
struct pt_regs *regs = task->thread.regs; struct pt_regs *regs = task->thread.regs;
if (regs != NULL) { if (regs != NULL) {
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) #if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
task->thread.dbcr0 = 0; task->thread.dbcr0 = 0;
regs->msr &= ~MSR_DE;
#else #else
regs->msr &= ~MSR_SE; regs->msr &= ~MSR_SE;
#endif #endif
......
...@@ -647,22 +647,22 @@ void SoftwareEmulation(struct pt_regs *regs) ...@@ -647,22 +647,22 @@ void SoftwareEmulation(struct pt_regs *regs)
} }
#endif /* CONFIG_8xx */ #endif /* CONFIG_8xx */
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) #if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
void DebugException(struct pt_regs *regs, unsigned long debug_status) void DebugException(struct pt_regs *regs, unsigned long debug_status)
{ {
#if 0
if (debug_status & DBSR_TIE) { /* trap instruction*/
if (!user_mode(regs) && debugger_bpt(regs))
return;
_exception(SIGTRAP, regs, 0, 0);
}
#endif
if (debug_status & DBSR_IC) { /* instruction completion */ if (debug_status & DBSR_IC) { /* instruction completion */
if (!user_mode(regs) && debugger_sstep(regs)) regs->msr &= ~MSR_DE;
return; if (user_mode(regs)) {
current->thread.dbcr0 &= ~DBCR0_IC; current->thread.dbcr0 &= ~DBCR0_IC;
} else {
/* Disable instruction completion */
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC);
/* Clear the instruction completion event */
mtspr(SPRN_DBSR, DBSR_IC);
if (debugger_sstep(regs))
return;
}
_exception(SIGTRAP, regs, TRAP_TRACE, 0); _exception(SIGTRAP, regs, TRAP_TRACE, 0);
} }
} }
......
...@@ -63,9 +63,9 @@ do { \ ...@@ -63,9 +63,9 @@ do { \
/* Default MSR for kernel mode. */ /* Default MSR for kernel mode. */
#if defined (CONFIG_40x) #if defined (CONFIG_40x)
#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE|MSR_DE) #define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE)
#elif defined(CONFIG_BOOKE) #elif defined(CONFIG_BOOKE)
#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_CE|MSR_DE) #define MSR_KERNEL (MSR_ME|MSR_RI|MSR_CE)
#endif #endif
/* Special Purpose Registers (SPRNs)*/ /* Special Purpose Registers (SPRNs)*/
......
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