|
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
|
|
|
#define SPFIX(code...)
|
|
|
#endif
|
|
|
|
|
|
- .macro svc_entry, stack_hole=0
|
|
|
+ .macro svc_entry, stack_hole=0, trace=1
|
|
|
UNWIND(.fnstart )
|
|
|
UNWIND(.save {r0 - pc} )
|
|
|
sub sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
|
|
@@ -182,9 +182,11 @@ ENDPROC(__und_invalid)
|
|
|
@
|
|
|
stmia r7, {r2 - r6}
|
|
|
|
|
|
+ .if \trace
|
|
|
#ifdef CONFIG_TRACE_IRQFLAGS
|
|
|
bl trace_hardirqs_off
|
|
|
#endif
|
|
|
+ .endif
|
|
|
.endm
|
|
|
|
|
|
.align 5
|
|
@@ -294,6 +296,15 @@ __pabt_svc:
|
|
|
UNWIND(.fnend )
|
|
|
ENDPROC(__pabt_svc)
|
|
|
|
|
|
+ .align 5
|
|
|
+__fiq_svc:
|
|
|
+ svc_entry trace=0
|
|
|
+ mov r0, sp @ struct pt_regs *regs
|
|
|
+ bl handle_fiq_as_nmi
|
|
|
+ svc_exit_via_fiq
|
|
|
+ UNWIND(.fnend )
|
|
|
+ENDPROC(__fiq_svc)
|
|
|
+
|
|
|
.align 5
|
|
|
.LCcralign:
|
|
|
.word cr_alignment
|
|
@@ -304,6 +315,46 @@ ENDPROC(__pabt_svc)
|
|
|
.LCfp:
|
|
|
.word fp_enter
|
|
|
|
|
|
+/*
|
|
|
+ * Abort mode handlers
|
|
|
+ */
|
|
|
+
|
|
|
+@
|
|
|
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
|
|
|
+@ and reuses the same macros. However in abort mode we must also
|
|
|
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
|
|
|
+@
|
|
|
+ .align 5
|
|
|
+__fiq_abt:
|
|
|
+ svc_entry trace=0
|
|
|
+
|
|
|
+ ARM( msr cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
|
|
|
+ THUMB( mov r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
|
|
|
+ THUMB( msr cpsr_c, r0 )
|
|
|
+ mov r1, lr @ Save lr_abt
|
|
|
+ mrs r2, spsr @ Save spsr_abt, abort is now safe
|
|
|
+ ARM( msr cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
|
|
|
+ THUMB( mov r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
|
|
|
+ THUMB( msr cpsr_c, r0 )
|
|
|
+ stmfd sp!, {r1 - r2}
|
|
|
+
|
|
|
+ add r0, sp, #8 @ struct pt_regs *regs
|
|
|
+ bl handle_fiq_as_nmi
|
|
|
+
|
|
|
+ ldmfd sp!, {r1 - r2}
|
|
|
+ ARM( msr cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
|
|
|
+ THUMB( mov r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
|
|
|
+ THUMB( msr cpsr_c, r0 )
|
|
|
+ mov lr, r1 @ Restore lr_abt, abort is unsafe
|
|
|
+ msr spsr_cxsf, r2 @ Restore spsr_abt
|
|
|
+ ARM( msr cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
|
|
|
+ THUMB( mov r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
|
|
|
+ THUMB( msr cpsr_c, r0 )
|
|
|
+
|
|
|
+ svc_exit_via_fiq
|
|
|
+ UNWIND(.fnend )
|
|
|
+ENDPROC(__fiq_abt)
|
|
|
+
|
|
|
/*
|
|
|
* User mode handlers
|
|
|
*
|
|
@@ -314,7 +365,7 @@ ENDPROC(__pabt_svc)
|
|
|
#error "sizeof(struct pt_regs) must be a multiple of 8"
|
|
|
#endif
|
|
|
|
|
|
- .macro usr_entry
|
|
|
+ .macro usr_entry, trace=1
|
|
|
UNWIND(.fnstart )
|
|
|
UNWIND(.cantunwind ) @ don't unwind the user space
|
|
|
sub sp, sp, #S_FRAME_SIZE
|
|
@@ -351,10 +402,12 @@ ENDPROC(__pabt_svc)
|
|
|
@
|
|
|
zero_fp
|
|
|
|
|
|
+ .if \trace
|
|
|
#ifdef CONFIG_IRQSOFF_TRACER
|
|
|
bl trace_hardirqs_off
|
|
|
#endif
|
|
|
ct_user_exit save = 0
|
|
|
+ .endif
|
|
|
.endm
|
|
|
|
|
|
.macro kuser_cmpxchg_check
|
|
@@ -683,6 +736,17 @@ ENTRY(ret_from_exception)
|
|
|
ENDPROC(__pabt_usr)
|
|
|
ENDPROC(ret_from_exception)
|
|
|
|
|
|
+ .align 5
|
|
|
+__fiq_usr:
|
|
|
+ usr_entry trace=0
|
|
|
+ kuser_cmpxchg_check
|
|
|
+ mov r0, sp @ struct pt_regs *regs
|
|
|
+ bl handle_fiq_as_nmi
|
|
|
+ get_thread_info tsk
|
|
|
+ restore_user_regs fast = 0, offset = 0
|
|
|
+ UNWIND(.fnend )
|
|
|
+ENDPROC(__fiq_usr)
|
|
|
+
|
|
|
/*
|
|
|
* Register switch for ARMv3 and ARMv4 processors
|
|
|
* r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
|
|
@@ -1118,17 +1182,29 @@ vector_addrexcptn:
|
|
|
b vector_addrexcptn
|
|
|
|
|
|
/*=============================================================================
|
|
|
- * Undefined FIQs
|
|
|
+ * FIQ "NMI" handler
|
|
|
*-----------------------------------------------------------------------------
|
|
|
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
|
|
|
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
|
|
|
- * Basically to switch modes, we *HAVE* to clobber one register... brain
|
|
|
- * damage alert! I don't think that we can execute any code in here in any
|
|
|
- * other mode than FIQ... Ok you can switch to another mode, but you can't
|
|
|
- * get out of that mode without clobbering one register.
|
|
|
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
|
|
|
+ * systems.
|
|
|
*/
|
|
|
-vector_fiq:
|
|
|
- subs pc, lr, #4
|
|
|
+ vector_stub fiq, FIQ_MODE, 4
|
|
|
+
|
|
|
+ .long __fiq_usr @ 0 (USR_26 / USR_32)
|
|
|
+ .long __fiq_svc @ 1 (FIQ_26 / FIQ_32)
|
|
|
+ .long __fiq_svc @ 2 (IRQ_26 / IRQ_32)
|
|
|
+ .long __fiq_svc @ 3 (SVC_26 / SVC_32)
|
|
|
+ .long __fiq_svc @ 4
|
|
|
+ .long __fiq_svc @ 5
|
|
|
+ .long __fiq_svc @ 6
|
|
|
+ .long __fiq_abt @ 7
|
|
|
+ .long __fiq_svc @ 8
|
|
|
+ .long __fiq_svc @ 9
|
|
|
+ .long __fiq_svc @ a
|
|
|
+ .long __fiq_svc @ b
|
|
|
+ .long __fiq_svc @ c
|
|
|
+ .long __fiq_svc @ d
|
|
|
+ .long __fiq_svc @ e
|
|
|
+ .long __fiq_svc @ f
|
|
|
|
|
|
.globl vector_fiq_offset
|
|
|
.equ vector_fiq_offset, vector_fiq
|