[Blackfin] arch: fix gdb testing regression

When transferring to IRQ5 from an exception, save SYSCFG in memory across the
transfer and clear the trace bit.

When we get a single step exception, check whether we can safely clear the
trace bit in SYSCFG.  We can (and should) clear it after the first instruction
of the interrupt handler; the first insn saves SYSCFG to the stack in all
handlers.

Signed-off-by: Bernd Schmidt <bernds_cb1@t-online.de>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
This commit is contained in:
Bernd Schmidt 2008-05-07 11:41:26 +08:00 committed by Bryan Wu
parent 8513c42edb
commit 0893f1250f
3 changed files with 87 additions and 31 deletions

View File

@ -151,26 +151,62 @@ ENTRY(_ex_soft_bp)
ENDPROC(_ex_soft_bp)
ENTRY(_ex_single_step)
/* If we just returned from an interrupt, the single step event is
for the RTI instruction. */
r7 = retx;
r6 = reti;
cc = r7 == r6;
if cc jump _bfin_return_from_exception
if cc jump _bfin_return_from_exception;
/* If we were in user mode, do the single step normally. */
p5.l = lo(IPEND);
p5.h = hi(IPEND);
r6 = [p5];
r7 = 0xffe0 (z);
r7 = r7 & r6;
cc = r7 == 0;
if !cc jump 1f;
/* Single stepping only a single instruction, so clear the trace
* bit here. */
r7 = syscfg;
bitclr (r7, 0);
syscfg = R7;
jump _ex_trap_c;
1:
/*
* We were in an interrupt handler. By convention, all of them save
* SYSCFG with their first instruction, so by checking whether our
* RETX points at the entry point, we can determine whether to allow
* a single step, or whether to clear SYSCFG.
*
* First, find out the interrupt level and the event vector for it.
*/
p5.l = lo(EVT0);
p5.h = hi(EVT0);
p5 += -4;
2:
r7 = rot r7 by -1;
p5 += 4;
if !cc jump 2b;
/* What we actually do is test for the _second_ instruction in the
* IRQ handler. That way, if there are insns following the restore
* of SYSCFG after leaving the handler, we will not turn off SYSCFG
* for them. */
r7 = [p5];
r7 += 2;
r6 = RETX;
cc = R7 == R6;
if !cc jump _bfin_return_from_exception;
r7 = syscfg;
bitclr (r7, 0);
syscfg = R7;
p5.l = lo(IPEND);
p5.h = hi(IPEND);
r6 = [p5];
cc = bittst(r6, 5);
if !cc jump _ex_trap_c;
p4.l = lo(EVT5);
p4.h = hi(EVT5);
r6.h = _exception_to_level5;
r6.l = _exception_to_level5;
r7 = [p4];
cc = r6 == r7;
if !cc jump _ex_trap_c;
/* Fall through to _bfin_return_from_exception. */
ENDPROC(_ex_single_step)
ENTRY(_bfin_return_from_exception)
@ -234,20 +270,26 @@ ENTRY(_ex_trap_c)
p5.l = _saved_icplb_fault_addr;
[p5] = r7;
p4.l = __retx;
p4.h = __retx;
p4.l = _excpt_saved_stuff;
p4.h = _excpt_saved_stuff;
r6 = retx;
[p4] = r6;
p4.l = lo(SAFE_USER_INSTRUCTION);
p4.h = hi(SAFE_USER_INSTRUCTION);
retx = p4;
r6 = SYSCFG;
[p4 + 4] = r6;
BITCLR(r6, 0);
SYSCFG = r6;
/* Disable all interrupts, but make sure level 5 is enabled so
* we can switch to that level. Save the old mask. */
cli r6;
p4.l = _excpt_saved_imask;
p4.h = _excpt_saved_imask;
[p4] = r6;
[p4 + 8] = r6;
p4.l = lo(SAFE_USER_INSTRUCTION);
p4.h = hi(SAFE_USER_INSTRUCTION);
retx = p4;
r6 = 0x3f;
sti r6;
@ -312,16 +354,17 @@ ENDPROC(_double_fault)
ENTRY(_exception_to_level5)
SAVE_ALL_SYS
p4.l = __retx;
p4.h = __retx;
p4.l = _excpt_saved_stuff;
p4.h = _excpt_saved_stuff;
r6 = [p4];
[sp + PT_PC] = r6;
r6 = [p4 + 4];
[sp + PT_SYSCFG] = r6;
/* Restore interrupt mask. We haven't pushed RETI, so this
* doesn't enable interrupts until we return from this handler. */
p4.l = _excpt_saved_imask;
p4.h = _excpt_saved_imask;
r6 = [p4];
r6 = [p4 + 8];
sti r6;
/* Restore the hardware error vector. */
@ -1349,7 +1392,14 @@ ENTRY(_sys_call_table)
.rept NR_syscalls-(.-_sys_call_table)/4
.long _sys_ni_syscall
.endr
_excpt_saved_imask:
/*
* Used to save the real RETX, IMASK and SYSCFG when temporarily
* storing safe values across the transition from exception to IRQ5.
*/
_excpt_saved_stuff:
.long 0;
.long 0;
.long 0;
_exception_stack:
@ -1363,7 +1413,3 @@ _exception_stack_top:
_last_cplb_fault_retx:
.long 0;
#endif
/* Used to save the real RETX when temporarily storing a safe
* return address. */
__retx:
.long 0;

View File

@ -17,6 +17,11 @@
#define PF_DTRACE_OFF 1
#define PF_DTRACE_BIT 5
/*
* NOTE! The single-stepping code assumes that all interrupt handlers
* start by saving SYSCFG on the stack with their first instruction.
*/
/* This one is used for exceptions, emulation, and NMI. It doesn't push
RETI and doesn't do cli. */
#define SAVE_ALL_SYS save_context_no_interrupts

View File

@ -27,6 +27,11 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* NOTE! The single-stepping code assumes that all interrupt handlers
* start by saving SYSCFG on the stack with their first instruction.
*/
/*
* Code to save processor context.
* We even save the register which are preserved by a function call