OSDN Git Service

ARM: 8266/1: Remove early stack deallocation from restore_user_regs
authorDaniel Thompson <daniel.thompson@linaro.org>
Fri, 9 Jan 2015 17:30:13 +0000 (18:30 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 12 Jan 2015 19:26:57 +0000 (19:26 +0000)
Currently restore_user_regs deallocates the SVC stack early in
its execution and relies on no exception being taken between
the deallocation and the registers being restored. The introduction
of a default FIQ handler that also uses the SVC stack breaks this
assumption and can result in corrupted register state.

This patch works around the problem by removing the early
stack deallocation and using r2 as a temporary instead. I have
not found a way to do this without introducing an extra mov
instruction to the macro.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/kernel/entry-header.S

index 4176df7..1a0045a 100644 (file)
        .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
+       mov     r2, sp
+       ldr     r1, [r2, #\offset + S_PSR]      @ get calling cpsr
+       ldr     lr, [r2, #\offset + S_PC]!      @ get pc
        msr     spsr_cxsf, r1                   @ save in spsr_svc
 #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K)
        @ We must avoid clrex due to Cortex-A15 erratum #830321
-       strex   r1, r2, [sp]                    @ clear the exclusive monitor
+       strex   r1, r2, [r2]                    @ clear the exclusive monitor
 #endif
        .if     \fast
-       ldmdb   sp, {r1 - lr}^                  @ get calling r1 - lr
+       ldmdb   r2, {r1 - lr}^                  @ get calling r1 - lr
        .else
-       ldmdb   sp, {r0 - lr}^                  @ get calling r0 - lr
+       ldmdb   r2, {r0 - lr}^                  @ get calling r0 - lr
        .endif
        mov     r0, r0                          @ ARMv5T and earlier require a nop
                                                @ after ldm {}^
-       add     sp, sp, #S_FRAME_SIZE - S_PC
+       add     sp, sp, #\offset + S_FRAME_SIZE
        movs    pc, lr                          @ return & move spsr_svc into cpsr
        .endm