ARM: entry: rejig register allocation in exception entry handlers
This allows us to avoid moving registers twice to work around the clobbered registers when we add calls to trace_hardirqs_{on,off}. Ensure that all SVC handlers return with SPSR in r5 for consistency. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
@@ -45,7 +45,7 @@
|
|||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro pabt_helper
|
.macro pabt_helper
|
||||||
mov r0, r2 @ pass address of aborted instruction.
|
mov r0, r4 @ pass address of aborted instruction.
|
||||||
#ifdef MULTI_PABORT
|
#ifdef MULTI_PABORT
|
||||||
ldr ip, .LCprocfns
|
ldr ip, .LCprocfns
|
||||||
mov lr, pc
|
mov lr, pc
|
||||||
@@ -56,6 +56,8 @@
|
|||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro dabt_helper
|
.macro dabt_helper
|
||||||
|
mov r2, r4
|
||||||
|
mov r3, r5
|
||||||
|
|
||||||
@
|
@
|
||||||
@ Call the processor-specific abort handler:
|
@ Call the processor-specific abort handler:
|
||||||
@@ -157,26 +159,26 @@ ENDPROC(__und_invalid)
|
|||||||
SPFIX( subeq sp, sp, #4 )
|
SPFIX( subeq sp, sp, #4 )
|
||||||
stmia sp, {r1 - r12}
|
stmia sp, {r1 - r12}
|
||||||
|
|
||||||
ldmia r0, {r1 - r3}
|
ldmia r0, {r3 - r5}
|
||||||
add r5, sp, #S_SP - 4 @ here for interlock avoidance
|
add r7, sp, #S_SP - 4 @ here for interlock avoidance
|
||||||
mov r4, #-1 @ "" "" "" ""
|
mov r6, #-1 @ "" "" "" ""
|
||||||
add r0, sp, #(S_FRAME_SIZE + \stack_hole - 4)
|
add r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
|
||||||
SPFIX( addeq r0, r0, #4 )
|
SPFIX( addeq r2, r2, #4 )
|
||||||
str r1, [sp, #-4]! @ save the "real" r0 copied
|
str r3, [sp, #-4]! @ save the "real" r0 copied
|
||||||
@ from the exception stack
|
@ from the exception stack
|
||||||
|
|
||||||
mov r1, lr
|
mov r3, lr
|
||||||
|
|
||||||
@
|
@
|
||||||
@ We are now ready to fill in the remaining blanks on the stack:
|
@ We are now ready to fill in the remaining blanks on the stack:
|
||||||
@
|
@
|
||||||
@ r0 - sp_svc
|
@ r2 - sp_svc
|
||||||
@ r1 - lr_svc
|
@ r3 - lr_svc
|
||||||
@ r2 - lr_<exception>, already fixed up for correct return/restart
|
@ r4 - lr_<exception>, already fixed up for correct return/restart
|
||||||
@ r3 - spsr_<exception>
|
@ r5 - spsr_<exception>
|
||||||
@ r4 - orig_r0 (see pt_regs definition in ptrace.h)
|
@ r6 - orig_r0 (see pt_regs definition in ptrace.h)
|
||||||
@
|
@
|
||||||
stmia r5, {r0 - r4}
|
stmia r7, {r2 - r6}
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.align 5
|
.align 5
|
||||||
@@ -187,7 +189,7 @@ __dabt_svc:
|
|||||||
@ get ready to re-enable interrupts if appropriate
|
@ get ready to re-enable interrupts if appropriate
|
||||||
@
|
@
|
||||||
mrs r9, cpsr
|
mrs r9, cpsr
|
||||||
tst r3, #PSR_I_BIT
|
tst r5, #PSR_I_BIT
|
||||||
biceq r9, r9, #PSR_I_BIT
|
biceq r9, r9, #PSR_I_BIT
|
||||||
|
|
||||||
dabt_helper
|
dabt_helper
|
||||||
@@ -208,8 +210,8 @@ __dabt_svc:
|
|||||||
@
|
@
|
||||||
@ restore SPSR and restart the instruction
|
@ restore SPSR and restart the instruction
|
||||||
@
|
@
|
||||||
ldr r2, [sp, #S_PSR]
|
ldr r5, [sp, #S_PSR]
|
||||||
svc_exit r2 @ return from exception
|
svc_exit r5 @ return from exception
|
||||||
UNWIND(.fnend )
|
UNWIND(.fnend )
|
||||||
ENDPROC(__dabt_svc)
|
ENDPROC(__dabt_svc)
|
||||||
|
|
||||||
@@ -232,13 +234,13 @@ __irq_svc:
|
|||||||
tst r0, #_TIF_NEED_RESCHED
|
tst r0, #_TIF_NEED_RESCHED
|
||||||
blne svc_preempt
|
blne svc_preempt
|
||||||
#endif
|
#endif
|
||||||
ldr r4, [sp, #S_PSR] @ irqs are already disabled
|
ldr r5, [sp, #S_PSR]
|
||||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||||
@ The parent context IRQs must have been enabled to get here in
|
@ The parent context IRQs must have been enabled to get here in
|
||||||
@ the first place, so there's no point checking the PSR I bit.
|
@ the first place, so there's no point checking the PSR I bit.
|
||||||
bl trace_hardirqs_on
|
bl trace_hardirqs_on
|
||||||
#endif
|
#endif
|
||||||
svc_exit r4 @ return from exception
|
svc_exit r5 @ return from exception
|
||||||
UNWIND(.fnend )
|
UNWIND(.fnend )
|
||||||
ENDPROC(__irq_svc)
|
ENDPROC(__irq_svc)
|
||||||
|
|
||||||
@@ -273,15 +275,16 @@ __und_svc:
|
|||||||
@ r0 - instruction
|
@ r0 - instruction
|
||||||
@
|
@
|
||||||
#ifndef CONFIG_THUMB2_KERNEL
|
#ifndef CONFIG_THUMB2_KERNEL
|
||||||
ldr r0, [r2, #-4]
|
ldr r0, [r4, #-4]
|
||||||
#else
|
#else
|
||||||
ldrh r0, [r2, #-2] @ Thumb instruction at LR - 2
|
ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2
|
||||||
and r9, r0, #0xf800
|
and r9, r0, #0xf800
|
||||||
cmp r9, #0xe800 @ 32-bit instruction if xx >= 0
|
cmp r9, #0xe800 @ 32-bit instruction if xx >= 0
|
||||||
ldrhhs r9, [r2] @ bottom 16 bits
|
ldrhhs r9, [r4] @ bottom 16 bits
|
||||||
orrhs r0, r9, r0, lsl #16
|
orrhs r0, r9, r0, lsl #16
|
||||||
#endif
|
#endif
|
||||||
adr r9, BSYM(1f)
|
adr r9, BSYM(1f)
|
||||||
|
mov r2, r4
|
||||||
bl call_fpe
|
bl call_fpe
|
||||||
|
|
||||||
mov r0, sp @ struct pt_regs *regs
|
mov r0, sp @ struct pt_regs *regs
|
||||||
@@ -295,8 +298,8 @@ __und_svc:
|
|||||||
@
|
@
|
||||||
@ restore SPSR and restart the instruction
|
@ restore SPSR and restart the instruction
|
||||||
@
|
@
|
||||||
ldr r2, [sp, #S_PSR] @ Get SVC cpsr
|
ldr r5, [sp, #S_PSR] @ Get SVC cpsr
|
||||||
svc_exit r2 @ return from exception
|
svc_exit r5 @ return from exception
|
||||||
UNWIND(.fnend )
|
UNWIND(.fnend )
|
||||||
ENDPROC(__und_svc)
|
ENDPROC(__und_svc)
|
||||||
|
|
||||||
@@ -308,7 +311,7 @@ __pabt_svc:
|
|||||||
@ re-enable interrupts if appropriate
|
@ re-enable interrupts if appropriate
|
||||||
@
|
@
|
||||||
mrs r9, cpsr
|
mrs r9, cpsr
|
||||||
tst r3, #PSR_I_BIT
|
tst r5, #PSR_I_BIT
|
||||||
biceq r9, r9, #PSR_I_BIT
|
biceq r9, r9, #PSR_I_BIT
|
||||||
|
|
||||||
pabt_helper
|
pabt_helper
|
||||||
@@ -325,8 +328,8 @@ __pabt_svc:
|
|||||||
@
|
@
|
||||||
@ restore SPSR and restart the instruction
|
@ restore SPSR and restart the instruction
|
||||||
@
|
@
|
||||||
ldr r2, [sp, #S_PSR]
|
ldr r5, [sp, #S_PSR]
|
||||||
svc_exit r2 @ return from exception
|
svc_exit r5 @ return from exception
|
||||||
UNWIND(.fnend )
|
UNWIND(.fnend )
|
||||||
ENDPROC(__pabt_svc)
|
ENDPROC(__pabt_svc)
|
||||||
|
|
||||||
@@ -357,23 +360,23 @@ ENDPROC(__pabt_svc)
|
|||||||
ARM( stmib sp, {r1 - r12} )
|
ARM( stmib sp, {r1 - r12} )
|
||||||
THUMB( stmia sp, {r0 - r12} )
|
THUMB( stmia sp, {r0 - r12} )
|
||||||
|
|
||||||
ldmia r0, {r1 - r3}
|
ldmia r0, {r3 - r5}
|
||||||
add r0, sp, #S_PC @ here for interlock avoidance
|
add r0, sp, #S_PC @ here for interlock avoidance
|
||||||
mov r4, #-1 @ "" "" "" ""
|
mov r6, #-1 @ "" "" "" ""
|
||||||
|
|
||||||
str r1, [sp] @ save the "real" r0 copied
|
str r3, [sp] @ save the "real" r0 copied
|
||||||
@ from the exception stack
|
@ from the exception stack
|
||||||
|
|
||||||
@
|
@
|
||||||
@ We are now ready to fill in the remaining blanks on the stack:
|
@ We are now ready to fill in the remaining blanks on the stack:
|
||||||
@
|
@
|
||||||
@ r2 - lr_<exception>, already fixed up for correct return/restart
|
@ r4 - lr_<exception>, already fixed up for correct return/restart
|
||||||
@ r3 - spsr_<exception>
|
@ r5 - spsr_<exception>
|
||||||
@ r4 - orig_r0 (see pt_regs definition in ptrace.h)
|
@ r6 - orig_r0 (see pt_regs definition in ptrace.h)
|
||||||
@
|
@
|
||||||
@ Also, separately save sp_usr and lr_usr
|
@ Also, separately save sp_usr and lr_usr
|
||||||
@
|
@
|
||||||
stmia r0, {r2 - r4}
|
stmia r0, {r4 - r6}
|
||||||
ARM( stmdb r0, {sp, lr}^ )
|
ARM( stmdb r0, {sp, lr}^ )
|
||||||
THUMB( store_user_sp_lr r0, r1, S_SP - S_PC )
|
THUMB( store_user_sp_lr r0, r1, S_SP - S_PC )
|
||||||
|
|
||||||
@@ -397,7 +400,7 @@ ENDPROC(__pabt_svc)
|
|||||||
@ if it was interrupted in a critical region. Here we
|
@ if it was interrupted in a critical region. Here we
|
||||||
@ perform a quick test inline since it should be false
|
@ perform a quick test inline since it should be false
|
||||||
@ 99.9999% of the time. The rest is done out of line.
|
@ 99.9999% of the time. The rest is done out of line.
|
||||||
cmp r2, #TASK_SIZE
|
cmp r4, #TASK_SIZE
|
||||||
blhs kuser_cmpxchg_fixup
|
blhs kuser_cmpxchg_fixup
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -441,6 +444,8 @@ ENDPROC(__irq_usr)
|
|||||||
.align 5
|
.align 5
|
||||||
__und_usr:
|
__und_usr:
|
||||||
usr_entry
|
usr_entry
|
||||||
|
mov r2, r4
|
||||||
|
mov r3, r5
|
||||||
|
|
||||||
@
|
@
|
||||||
@ fall through to the emulation code, which returns using r9 if
|
@ fall through to the emulation code, which returns using r9 if
|
||||||
@@ -894,13 +899,13 @@ __kuser_cmpxchg: @ 0xffff0fc0
|
|||||||
.text
|
.text
|
||||||
kuser_cmpxchg_fixup:
|
kuser_cmpxchg_fixup:
|
||||||
@ Called from kuser_cmpxchg_check macro.
|
@ Called from kuser_cmpxchg_check macro.
|
||||||
@ r2 = address of interrupted insn (must be preserved).
|
@ r4 = address of interrupted insn (must be preserved).
|
||||||
@ sp = saved regs. r7 and r8 are clobbered.
|
@ sp = saved regs. r7 and r8 are clobbered.
|
||||||
@ 1b = first critical insn, 2b = last critical insn.
|
@ 1b = first critical insn, 2b = last critical insn.
|
||||||
@ If r2 >= 1b and r2 <= 2b then saved pc_usr is set to 1b.
|
@ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b.
|
||||||
mov r7, #0xffff0fff
|
mov r7, #0xffff0fff
|
||||||
sub r7, r7, #(0xffff0fff - (0xffff0fc0 + (1b - __kuser_cmpxchg)))
|
sub r7, r7, #(0xffff0fff - (0xffff0fc0 + (1b - __kuser_cmpxchg)))
|
||||||
subs r8, r2, r7
|
subs r8, r4, r7
|
||||||
rsbcss r8, r8, #(2b - 1b)
|
rsbcss r8, r8, #(2b - 1b)
|
||||||
strcs r7, [sp, #S_PC]
|
strcs r7, [sp, #S_PC]
|
||||||
mov pc, lr
|
mov pc, lr
|
||||||
|
Reference in New Issue
Block a user