[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:
parent
8513c42edb
commit
0893f1250f
|
@ -151,26 +151,62 @@ ENTRY(_ex_soft_bp)
|
||||||
ENDPROC(_ex_soft_bp)
|
ENDPROC(_ex_soft_bp)
|
||||||
|
|
||||||
ENTRY(_ex_single_step)
|
ENTRY(_ex_single_step)
|
||||||
|
/* If we just returned from an interrupt, the single step event is
|
||||||
|
for the RTI instruction. */
|
||||||
r7 = retx;
|
r7 = retx;
|
||||||
r6 = reti;
|
r6 = reti;
|
||||||
cc = r7 == r6;
|
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;
|
r7 = syscfg;
|
||||||
bitclr (r7, 0);
|
bitclr (r7, 0);
|
||||||
syscfg = R7;
|
syscfg = R7;
|
||||||
|
|
||||||
p5.l = lo(IPEND);
|
/* Fall through to _bfin_return_from_exception. */
|
||||||
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;
|
|
||||||
ENDPROC(_ex_single_step)
|
ENDPROC(_ex_single_step)
|
||||||
|
|
||||||
ENTRY(_bfin_return_from_exception)
|
ENTRY(_bfin_return_from_exception)
|
||||||
|
@ -234,20 +270,26 @@ ENTRY(_ex_trap_c)
|
||||||
p5.l = _saved_icplb_fault_addr;
|
p5.l = _saved_icplb_fault_addr;
|
||||||
[p5] = r7;
|
[p5] = r7;
|
||||||
|
|
||||||
p4.l = __retx;
|
p4.l = _excpt_saved_stuff;
|
||||||
p4.h = __retx;
|
p4.h = _excpt_saved_stuff;
|
||||||
|
|
||||||
r6 = retx;
|
r6 = retx;
|
||||||
[p4] = r6;
|
[p4] = r6;
|
||||||
p4.l = lo(SAFE_USER_INSTRUCTION);
|
|
||||||
p4.h = hi(SAFE_USER_INSTRUCTION);
|
r6 = SYSCFG;
|
||||||
retx = p4;
|
[p4 + 4] = r6;
|
||||||
|
BITCLR(r6, 0);
|
||||||
|
SYSCFG = r6;
|
||||||
|
|
||||||
/* Disable all interrupts, but make sure level 5 is enabled so
|
/* Disable all interrupts, but make sure level 5 is enabled so
|
||||||
* we can switch to that level. Save the old mask. */
|
* we can switch to that level. Save the old mask. */
|
||||||
cli r6;
|
cli r6;
|
||||||
p4.l = _excpt_saved_imask;
|
[p4 + 8] = r6;
|
||||||
p4.h = _excpt_saved_imask;
|
|
||||||
[p4] = r6;
|
p4.l = lo(SAFE_USER_INSTRUCTION);
|
||||||
|
p4.h = hi(SAFE_USER_INSTRUCTION);
|
||||||
|
retx = p4;
|
||||||
|
|
||||||
r6 = 0x3f;
|
r6 = 0x3f;
|
||||||
sti r6;
|
sti r6;
|
||||||
|
|
||||||
|
@ -312,16 +354,17 @@ ENDPROC(_double_fault)
|
||||||
ENTRY(_exception_to_level5)
|
ENTRY(_exception_to_level5)
|
||||||
SAVE_ALL_SYS
|
SAVE_ALL_SYS
|
||||||
|
|
||||||
p4.l = __retx;
|
p4.l = _excpt_saved_stuff;
|
||||||
p4.h = __retx;
|
p4.h = _excpt_saved_stuff;
|
||||||
r6 = [p4];
|
r6 = [p4];
|
||||||
[sp + PT_PC] = r6;
|
[sp + PT_PC] = r6;
|
||||||
|
|
||||||
|
r6 = [p4 + 4];
|
||||||
|
[sp + PT_SYSCFG] = r6;
|
||||||
|
|
||||||
/* Restore interrupt mask. We haven't pushed RETI, so this
|
/* Restore interrupt mask. We haven't pushed RETI, so this
|
||||||
* doesn't enable interrupts until we return from this handler. */
|
* doesn't enable interrupts until we return from this handler. */
|
||||||
p4.l = _excpt_saved_imask;
|
r6 = [p4 + 8];
|
||||||
p4.h = _excpt_saved_imask;
|
|
||||||
r6 = [p4];
|
|
||||||
sti r6;
|
sti r6;
|
||||||
|
|
||||||
/* Restore the hardware error vector. */
|
/* Restore the hardware error vector. */
|
||||||
|
@ -1349,7 +1392,14 @@ ENTRY(_sys_call_table)
|
||||||
.rept NR_syscalls-(.-_sys_call_table)/4
|
.rept NR_syscalls-(.-_sys_call_table)/4
|
||||||
.long _sys_ni_syscall
|
.long _sys_ni_syscall
|
||||||
.endr
|
.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;
|
.long 0;
|
||||||
|
|
||||||
_exception_stack:
|
_exception_stack:
|
||||||
|
@ -1363,7 +1413,3 @@ _exception_stack_top:
|
||||||
_last_cplb_fault_retx:
|
_last_cplb_fault_retx:
|
||||||
.long 0;
|
.long 0;
|
||||||
#endif
|
#endif
|
||||||
/* Used to save the real RETX when temporarily storing a safe
|
|
||||||
* return address. */
|
|
||||||
__retx:
|
|
||||||
.long 0;
|
|
||||||
|
|
|
@ -17,6 +17,11 @@
|
||||||
#define PF_DTRACE_OFF 1
|
#define PF_DTRACE_OFF 1
|
||||||
#define PF_DTRACE_BIT 5
|
#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
|
/* This one is used for exceptions, emulation, and NMI. It doesn't push
|
||||||
RETI and doesn't do cli. */
|
RETI and doesn't do cli. */
|
||||||
#define SAVE_ALL_SYS save_context_no_interrupts
|
#define SAVE_ALL_SYS save_context_no_interrupts
|
||||||
|
|
|
@ -27,6 +27,11 @@
|
||||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
* 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.
|
* Code to save processor context.
|
||||||
* We even save the register which are preserved by a function call
|
* We even save the register which are preserved by a function call
|
||||||
|
|
Reference in New Issue