X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=arch%2Fblackfin%2Fmach-common%2Fentry.S;h=4bd971e81f1f695b75ac09bf4ac1f0f93770bf88;hb=b42a9f442c6f9f47a9d63f66fcc67ab8efe7b7fa;hp=cee54cebbc6592505e0ff2046a7cc94d2b792c15;hpb=62429f434091586d54b37b8dd46076e7c08b27b9;p=deliverable%2Flinux.git diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index cee54cebbc65..4bd971e81f1f 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -38,6 +38,7 @@ #include #include #include +#include #include /* TIF_NEED_RESCHED */ #include #include @@ -52,15 +53,6 @@ # define EX_SCRATCH_REG CYCLES #endif -#if ANOMALY_05000281 -ENTRY(_safe_speculative_execution) - NOP; - NOP; - NOP; - jump _safe_speculative_execution; -ENDPROC(_safe_speculative_execution) -#endif - #ifdef CONFIG_EXCPT_IRQ_SYSC_L1 .section .l1.text #else @@ -121,10 +113,14 @@ ENTRY(_ex_icplb_miss) (R7:6,P5:4) = [sp++]; ASTAT = [sp++]; SAVE_ALL_SYS - DEBUG_HWTRACE_SAVE(p5, r7) #ifdef CONFIG_MPU + /* We must load R1 here, _before_ DEBUG_HWTRACE_SAVE, since that + * will change the stack pointer. */ R0 = SEQSTAT; R1 = SP; +#endif + DEBUG_HWTRACE_SAVE(p5, r7) +#ifdef CONFIG_MPU sp += -12; call _cplb_hdr; sp += 12; @@ -155,26 +151,96 @@ 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; +#ifdef CONFIG_KGDB + /* Don't do single step in hardware exception handler */ + p5.l = lo(IPEND); + p5.h = hi(IPEND); + r6 = [p5]; + cc = bittst(r6, 4); + if cc jump _bfin_return_from_exception; + cc = bittst(r6, 5); + if cc jump _bfin_return_from_exception; + + /* skip single step if current interrupt priority is higher than + * that of the first instruction, from which gdb starts single step */ + r6 >>= 6; + r7 = 10; +.Lfind_priority_start: + cc = bittst(r6, 0); + if cc jump .Lfind_priority_done; + r6 >>= 1; + r7 += -1; + cc = r7 == 0; + if cc jump .Lfind_priority_done; + jump.s .Lfind_priority_start; +.Lfind_priority_done: + p4.l = _debugger_step; + p4.h = _debugger_step; + r6 = [p4]; + cc = r6 == 0; + if cc jump .Ldo_single_step; + r6 += -1; + cc = r6 < r7; + if cc jump 1f; +.Ldo_single_step: +#else + /* 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; +#endif + + /* 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) @@ -191,6 +257,7 @@ ENTRY(_bfin_return_from_exception) ENDPROC(_bfin_return_from_exception) ENTRY(_handle_bad_cplb) + DEBUG_HWTRACE_RESTORE(p5, r7) /* To get here, we just tried and failed to change a CPLB * so, handle things in trap_c (C code), by lowering to * IRQ5, just like we normally do. Since this is not a @@ -225,32 +292,41 @@ ENTRY(_ex_trap_c) [p4] = p5; csync; + p4.l = lo(DCPLB_FAULT_ADDR); + p4.h = hi(DCPLB_FAULT_ADDR); + r7 = [p4]; + p5.h = _saved_dcplb_fault_addr; + p5.l = _saved_dcplb_fault_addr; + [p5] = r7; + + r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)]; + p5.h = _saved_icplb_fault_addr; + p5.l = _saved_icplb_fault_addr; + [p5] = r7; + + p4.l = _excpt_saved_stuff; + p4.h = _excpt_saved_stuff; + + r6 = retx; + [p4] = r6; + + 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; - /* Save the excause into a circular buffer, in case the instruction - * which caused this excecptions causes others. - */ - P5.l = _in_ptr_excause; - P5.h = _in_ptr_excause; - R7 = [P5]; - R7 += 4; - R6 = 0xF; - R7 = R7 & R6; - [P5] = R7; - R6.l = _excause_circ_buf; - R6.h = _excause_circ_buf; - R7 = R7 + R6; - p5 = R7; - R6 = SEQSTAT; - [P5] = R6; - (R7:6,P5:4) = [sp++]; ASTAT = [sp++]; SP = EX_SCRATCH_REG; @@ -295,6 +371,11 @@ ENTRY(_double_fault) */ SAVE_ALL_SYS + /* The dumping functions expect the return address in the RETI + * slot. */ + r6 = retx; + [sp + PT_PC] = r6; + r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ SP += -12; call _double_fault_c; @@ -307,11 +388,17 @@ ENDPROC(_double_fault) ENTRY(_exception_to_level5) SAVE_ALL_SYS + 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. */ @@ -328,42 +415,11 @@ ENTRY(_exception_to_level5) r0 = [p2]; /* Read current IPEND */ [sp + PT_IPEND] = r0; /* Store IPEND */ - /* Pop the excause from the circular buffer and push it on the stack - * (in the right place - if you change the location of SEQSTAT, you - * must change this offset. - */ -.L_excep_to_5_again: - P5.l = _out_ptr_excause; - P5.h = _out_ptr_excause; - R7 = [P5]; - R7 += 4; - R6 = 0xF; - R7 = R7 & R6; - [P5] = R7; - R6.l = _excause_circ_buf; - R6.h = _excause_circ_buf; - R7 = R7 + R6; - P5 = R7; - R1 = [P5]; - [SP + PT_SEQSTAT] = r1; - r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ SP += -12; call _trap_c; SP += 12; - /* See if anything else is in the exception buffer - * if there is, process it - */ - P5.l = _out_ptr_excause; - P5.h = _out_ptr_excause; - P4.l = _in_ptr_excause; - P4.h = _in_ptr_excause; - R6 = [P5]; - R7 = [P4]; - CC = R6 == R7; - if ! CC JUMP .L_excep_to_5_again - call _ret_from_exception; RESTORE_ALL_SYS rti; @@ -727,8 +783,8 @@ ENTRY(_return_from_int) [p0] = p1; csync; #if ANOMALY_05000281 - r0.l = _safe_speculative_execution; - r0.h = _safe_speculative_execution; + r0.l = lo(SAFE_USER_INSTRUCTION); + r0.h = hi(SAFE_USER_INSTRUCTION); reti = r0; #endif r0 = 0x801f (z); @@ -741,8 +797,8 @@ ENDPROC(_return_from_int) ENTRY(_lower_to_irq14) #if ANOMALY_05000281 - r0.l = _safe_speculative_execution; - r0.h = _safe_speculative_execution; + r0.l = lo(SAFE_USER_INSTRUCTION); + r0.h = hi(SAFE_USER_INSTRUCTION); reti = r0; #endif r0 = 0x401f; @@ -809,20 +865,6 @@ _schedule_and_signal: rti; ENDPROC(_lower_to_irq14) -/* Make sure when we start, that the circular buffer is initialized properly - * R0 and P0 are call clobbered, so we can use them here. - */ -ENTRY(_init_exception_buff) - r0 = 0; - p0.h = _in_ptr_excause; - p0.l = _in_ptr_excause; - [p0] = r0; - p0.h = _out_ptr_excause; - p0.l = _out_ptr_excause; - [p0] = r0; - rts; -ENDPROC(_init_exception_buff) - /* We handle this 100% in exception space - to reduce overhead * Only potiential problem is if the software buffer gets swapped out of the * CPLB table - then double fault. - so we don't let this happen in other places @@ -1384,7 +1426,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: @@ -1398,17 +1447,3 @@ _exception_stack_top: _last_cplb_fault_retx: .long 0; #endif -/* - * Single instructions can have multiple faults, which need to be - * handled by traps.c, in irq5. We store the exception cause to ensure - * we don't miss a double fault condition - */ -ENTRY(_in_ptr_excause) - .long 0; -ENTRY(_out_ptr_excause) - .long 0; -ALIGN -ENTRY(_excause_circ_buf) - .rept 4 - .long 0 - .endr