Merge tag 'master-2014-10-08' of git://git.kernel.org/pub/scm/linux/kernel/git/linvil...
[firefly-linux-kernel-4.4.55.git] / arch / arm / kernel / entry-armv.S
index 36276cdccfbc71e9e69de18fe21a00ac25ddbd07..2f5555d307b345b7e0191adb7d7f02fe49ab887b 100644 (file)
@@ -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,13 +365,16 @@ 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
  ARM(  stmib   sp, {r1 - r12}  )
  THUMB(        stmia   sp, {r0 - r12}  )
 
+ ATRAP(        mrc     p15, 0, r7, c1, c0, 0)
+ ATRAP(        ldr     r8, .LCcralign)
+
        ldmia   r0, {r3 - r5}
        add     r0, sp, #S_PC           @ here for interlock avoidance
        mov     r6, #-1                 @  ""  ""     ""        ""
@@ -328,6 +382,8 @@ ENDPROC(__pabt_svc)
        str     r3, [sp]                @ save the "real" r0 copied
                                        @ from the exception stack
 
+ ATRAP(        ldr     r8, [r8, #0])
+
        @
        @ We are now ready to fill in the remaining blanks on the stack:
        @
@@ -341,20 +397,21 @@ ENDPROC(__pabt_svc)
  ARM(  stmdb   r0, {sp, lr}^                   )
  THUMB(        store_user_sp_lr r0, r1, S_SP - S_PC    )
 
-       @
        @ Enable the alignment trap while in kernel mode
-       @
-       alignment_trap r0, .LCcralign
+ ATRAP(        teq     r8, r7)
+ ATRAP( mcrne  p15, 0, r8, c1, c0, 0)
 
        @
        @ Clear FP to mark the first stack frame
        @
        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 +740,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 +1186,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