[ARM] 3256/1: Make the function-returning ldm's use sp as the base register

Patch from Catalin Marinas

If the low interrupt latency mode is enabled for the CPU (from ARMv6
onwards), the ldm/stm instructions are no longer atomic. An ldm instruction
restoring the sp and pc registers can be interrupted immediately after sp
was updated but before the pc. If this happens, the CPU restores the base
register to the value before the ldm instruction but if the base register
is not sp, the interrupt routine will corrupt the stack and the restarted
ldm instruction will load garbage.

Note that future ARM cores might always run in the low interrupt latency
mode.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by Catalin Marinas and committed by Russell King 90303b10 ece5f7b3

+13 -11
+2 -2
arch/arm/kernel/fiq.c
··· 101 ldmia %1, {r8 - r14}\n\ 102 msr cpsr_c, %0 @ return to SVC mode\n\ 103 mov r0, r0\n\ 104 - ldmea fp, {fp, sp, pc}" 105 : "=&r" (tmp) 106 : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); 107 } ··· 119 stmia %1, {r8 - r14}\n\ 120 msr cpsr_c, %0 @ return to SVC mode\n\ 121 mov r0, r0\n\ 122 - ldmea fp, {fp, sp, pc}" 123 : "=&r" (tmp) 124 : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); 125 }
··· 101 ldmia %1, {r8 - r14}\n\ 102 msr cpsr_c, %0 @ return to SVC mode\n\ 103 mov r0, r0\n\ 104 + ldmfd sp, {fp, sp, pc}" 105 : "=&r" (tmp) 106 : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); 107 } ··· 119 stmia %1, {r8 - r14}\n\ 120 msr cpsr_c, %0 @ return to SVC mode\n\ 121 mov r0, r0\n\ 122 + ldmfd sp, {fp, sp, pc}" 123 : "=&r" (tmp) 124 : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); 125 }
+4 -2
arch/arm/lib/csumpartialcopy.S
··· 18 */ 19 20 .macro save_regs 21 stmfd sp!, {r1, r4 - r8, fp, ip, lr, pc} 22 .endm 23 24 - .macro load_regs,flags 25 - LOADREGS(\flags,fp,{r1, r4 - r8, fp, sp, pc}) 26 .endm 27 28 .macro load1b, reg1
··· 18 */ 19 20 .macro save_regs 21 + mov ip, sp 22 stmfd sp!, {r1, r4 - r8, fp, ip, lr, pc} 23 + sub fp, ip, #4 24 .endm 25 26 + .macro load_regs 27 + ldmfd sp, {r1, r4 - r8, fp, sp, pc} 28 .endm 29 30 .macro load1b, reg1
+2 -4
arch/arm/lib/csumpartialcopygeneric.S
··· 23 sum .req r3 24 25 .Lzero: mov r0, sum 26 - load_regs ea 27 28 /* 29 * Align an unaligned destination pointer. We know that ··· 87 b .Ldone 88 89 FN_ENTRY 90 - mov ip, sp 91 save_regs 92 - sub fp, ip, #4 93 94 cmp len, #8 @ Ensure that we have at least 95 blo .Lless8 @ 8 bytes to copy. ··· 161 ldr sum, [sp, #0] @ dst 162 tst sum, #1 163 movne r0, r0, ror #8 164 - load_regs ea 165 166 .Lsrc_not_aligned: 167 adc sum, sum, #0 @ include C from dst alignment
··· 23 sum .req r3 24 25 .Lzero: mov r0, sum 26 + load_regs 27 28 /* 29 * Align an unaligned destination pointer. We know that ··· 87 b .Ldone 88 89 FN_ENTRY 90 save_regs 91 92 cmp len, #8 @ Ensure that we have at least 93 blo .Lless8 @ 8 bytes to copy. ··· 163 ldr sum, [sp, #0] @ dst 164 tst sum, #1 165 movne r0, r0, ror #8 166 + load_regs 167 168 .Lsrc_not_aligned: 169 adc sum, sum, #0 @ include C from dst alignment
+5 -3
arch/arm/lib/csumpartialcopyuser.S
··· 18 .text 19 20 .macro save_regs 21 stmfd sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc} 22 .endm 23 24 - .macro load_regs,flags 25 - ldm\flags fp, {r1, r2, r4-r8, fp, sp, pc} 26 .endm 27 28 .macro load1b, reg1 ··· 102 6002: teq r2, r1 103 strneb r0, [r1], #1 104 bne 6002b 105 - load_regs ea 106 .previous
··· 18 .text 19 20 .macro save_regs 21 + mov ip, sp 22 stmfd sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc} 23 + sub fp, ip, #4 24 .endm 25 26 + .macro load_regs 27 + ldmfd sp, {r1, r2, r4-r8, fp, sp, pc} 28 .endm 29 30 .macro load1b, reg1 ··· 100 6002: teq r2, r1 101 strneb r0, [r1], #1 102 bne 6002b 103 + load_regs 104 .previous