Skip to content

Commit

Permalink
[Blackfin] arch: fix gdb testing regression
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Bernd Schmidt authored and Bryan Wu committed May 7, 2008
1 parent 8513c42 commit 0893f12
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 31 deletions.
108 changes: 77 additions & 31 deletions arch/blackfin/mach-common/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
r7 = syscfg;
bitclr (r7, 0);
syscfg = R7;
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];
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;
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;

/* Fall through to _bfin_return_from_exception. */
ENDPROC(_ex_single_step)

ENTRY(_bfin_return_from_exception)
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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:
Expand All @@ -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;
5 changes: 5 additions & 0 deletions include/asm-blackfin/entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions include/asm-blackfin/mach-common/context.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0893f12

Please sign in to comment.