Thumb-2: Implementation of the unified start-up and exceptions code
[deliverable/linux.git] / arch / arm / kernel / entry-header.S
index 55c99cdab7d64f430f1e3063343111cfdf9dfce9..a4eaf4f920c58fbaa8c5cb6be285a7c4f684a376 100644 (file)
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/linkage.h>
 
 #endif
        .endm
 
-#if __LINUX_ARM_ARCH__ >= 6
-       .macro  disable_irq
-       cpsid   i
+       .macro  alignment_trap, rtemp
+#ifdef CONFIG_ALIGNMENT_TRAP
+       ldr     \rtemp, .LCcralign
+       ldr     \rtemp, [\rtemp]
+       mcr     p15, 0, \rtemp, c1, c0
+#endif
        .endm
 
-       .macro  enable_irq
-       cpsie   i
+       @
+       @ Store/load the USER SP and LR registers by switching to the SYS
+       @ mode. Useful in Thumb-2 mode where "stm/ldm rd, {sp, lr}^" is not
+       @ available. Should only be called from SVC mode
+       @
+       .macro  store_user_sp_lr, rd, rtemp, offset = 0
+       mrs     \rtemp, cpsr
+       eor     \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
+       msr     cpsr_c, \rtemp                  @ switch to the SYS mode
+
+       str     sp, [\rd, #\offset]             @ save sp_usr
+       str     lr, [\rd, #\offset + 4]         @ save lr_usr
+
+       eor     \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
+       msr     cpsr_c, \rtemp                  @ switch back to the SVC mode
        .endm
-#else
-       .macro  disable_irq
-       msr     cpsr_c, #PSR_I_BIT | SVC_MODE
+
+       .macro  load_user_sp_lr, rd, rtemp, offset = 0
+       mrs     \rtemp, cpsr
+       eor     \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
+       msr     cpsr_c, \rtemp                  @ switch to the SYS mode
+
+       ldr     sp, [\rd, #\offset]             @ load sp_usr
+       ldr     lr, [\rd, #\offset + 4]         @ load lr_usr
+
+       eor     \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
+       msr     cpsr_c, \rtemp                  @ switch back to the SVC mode
        .endm
 
-       .macro  enable_irq
-       msr     cpsr_c, #SVC_MODE
+#ifndef CONFIG_THUMB2_KERNEL
+       .macro  svc_exit, rpsr
+       msr     spsr_cxsf, \rpsr
+       ldmia   sp, {r0 - pc}^                  @ load r0 - pc, cpsr
+       .endm
+
+       .macro  restore_user_regs, fast = 0, offset = 0
+       ldr     r1, [sp, #\offset + S_PSR]      @ get calling cpsr
+       ldr     lr, [sp, #\offset + S_PC]!      @ get pc
+       msr     spsr_cxsf, r1                   @ save in spsr_svc
+       .if     \fast
+       ldmdb   sp, {r1 - lr}^                  @ get calling r1 - lr
+       .else
+       ldmdb   sp, {r0 - lr}^                  @ get calling r0 - lr
+       .endif
+       add     sp, sp, #S_FRAME_SIZE - S_PC
+       movs    pc, lr                          @ return & move spsr_svc into cpsr
        .endm
-#endif
 
        .macro  get_thread_info, rd
        mov     \rd, sp, lsr #13
        mov     \rd, \rd, lsl #13
        .endm
+#else  /* CONFIG_THUMB2_KERNEL */
+       .macro  svc_exit, rpsr
+       ldr     r0, [sp, #S_SP]                 @ top of the stack
+       ldr     r1, [sp, #S_PC]                 @ return address
+       tst     r0, #4                          @ orig stack 8-byte aligned?
+       stmdb   r0, {r1, \rpsr}                 @ rfe context
+       ldmia   sp, {r0 - r12}
+       ldr     lr, [sp, #S_LR]
+       addeq   sp, sp, #S_FRAME_SIZE - 8       @ aligned
+       addne   sp, sp, #S_FRAME_SIZE - 4       @ not aligned
+       rfeia   sp!
+       .endm
 
-       .macro  alignment_trap, rtemp
-#ifdef CONFIG_ALIGNMENT_TRAP
-       ldr     \rtemp, .LCcralign
-       ldr     \rtemp, [\rtemp]
-       mcr     p15, 0, \rtemp, c1, c0
-#endif
+       .macro  restore_user_regs, fast = 0, offset = 0
+       mov     r2, sp
+       load_user_sp_lr r2, r3, \offset + S_SP  @ calling sp, lr
+       ldr     r1, [sp, #\offset + S_PSR]      @ get calling cpsr
+       ldr     lr, [sp, #\offset + S_PC]       @ get pc
+       add     sp, sp, #\offset + S_SP
+       msr     spsr_cxsf, r1                   @ save in spsr_svc
+       .if     \fast
+       ldmdb   sp, {r1 - r12}                  @ get calling r1 - r12
+       .else
+       ldmdb   sp, {r0 - r12}                  @ get calling r0 - r12
+       .endif
+       add     sp, sp, #S_FRAME_SIZE - S_SP
+       movs    pc, lr                          @ return & move spsr_svc into cpsr
        .endm
 
+       .macro  get_thread_info, rd
+       mov     \rd, sp
+       lsr     \rd, \rd, #13
+       mov     \rd, \rd, lsl #13
+       .endm
+#endif /* !CONFIG_THUMB2_KERNEL */
 
 /*
  * These are the registers used in the syscall handler, and allow us to
This page took 0.026977 seconds and 5 git commands to generate.