diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2006-01-12 11:53:51 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-01-12 11:53:51 -0500 |
commit | 90303b102353302e84758f245906368907e6a23b (patch) | |
tree | 3e417666985ee5875c2d3435518de2c4bdc9b88d /arch | |
parent | ece5f7b3c4fde70a1ae4add7372ebca5c90bc34d (diff) |
[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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/kernel/fiq.c | 4 | ||||
-rw-r--r-- | arch/arm/lib/csumpartialcopy.S | 6 | ||||
-rw-r--r-- | arch/arm/lib/csumpartialcopygeneric.S | 6 | ||||
-rw-r--r-- | arch/arm/lib/csumpartialcopyuser.S | 8 |
4 files changed, 13 insertions, 11 deletions
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index 9299dfc25698..1ec3f7faa259 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c | |||
@@ -101,7 +101,7 @@ void __attribute__((naked)) set_fiq_regs(struct pt_regs *regs) | |||
101 | ldmia %1, {r8 - r14}\n\ | 101 | ldmia %1, {r8 - r14}\n\ |
102 | msr cpsr_c, %0 @ return to SVC mode\n\ | 102 | msr cpsr_c, %0 @ return to SVC mode\n\ |
103 | mov r0, r0\n\ | 103 | mov r0, r0\n\ |
104 | ldmea fp, {fp, sp, pc}" | 104 | ldmfd sp, {fp, sp, pc}" |
105 | : "=&r" (tmp) | 105 | : "=&r" (tmp) |
106 | : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); | 106 | : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); |
107 | } | 107 | } |
@@ -119,7 +119,7 @@ void __attribute__((naked)) get_fiq_regs(struct pt_regs *regs) | |||
119 | stmia %1, {r8 - r14}\n\ | 119 | stmia %1, {r8 - r14}\n\ |
120 | msr cpsr_c, %0 @ return to SVC mode\n\ | 120 | msr cpsr_c, %0 @ return to SVC mode\n\ |
121 | mov r0, r0\n\ | 121 | mov r0, r0\n\ |
122 | ldmea fp, {fp, sp, pc}" | 122 | ldmfd sp, {fp, sp, pc}" |
123 | : "=&r" (tmp) | 123 | : "=&r" (tmp) |
124 | : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); | 124 | : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); |
125 | } | 125 | } |
diff --git a/arch/arm/lib/csumpartialcopy.S b/arch/arm/lib/csumpartialcopy.S index 990ee63b2465..21effe0dbf97 100644 --- a/arch/arm/lib/csumpartialcopy.S +++ b/arch/arm/lib/csumpartialcopy.S | |||
@@ -18,11 +18,13 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | .macro save_regs | 20 | .macro save_regs |
21 | mov ip, sp | ||
21 | stmfd sp!, {r1, r4 - r8, fp, ip, lr, pc} | 22 | stmfd sp!, {r1, r4 - r8, fp, ip, lr, pc} |
23 | sub fp, ip, #4 | ||
22 | .endm | 24 | .endm |
23 | 25 | ||
24 | .macro load_regs,flags | 26 | .macro load_regs |
25 | LOADREGS(\flags,fp,{r1, r4 - r8, fp, sp, pc}) | 27 | ldmfd sp, {r1, r4 - r8, fp, sp, pc} |
26 | .endm | 28 | .endm |
27 | 29 | ||
28 | .macro load1b, reg1 | 30 | .macro load1b, reg1 |
diff --git a/arch/arm/lib/csumpartialcopygeneric.S b/arch/arm/lib/csumpartialcopygeneric.S index 4a4609c19095..c50e8f5285d1 100644 --- a/arch/arm/lib/csumpartialcopygeneric.S +++ b/arch/arm/lib/csumpartialcopygeneric.S | |||
@@ -23,7 +23,7 @@ len .req r2 | |||
23 | sum .req r3 | 23 | sum .req r3 |
24 | 24 | ||
25 | .Lzero: mov r0, sum | 25 | .Lzero: mov r0, sum |
26 | load_regs ea | 26 | load_regs |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * Align an unaligned destination pointer. We know that | 29 | * Align an unaligned destination pointer. We know that |
@@ -87,9 +87,7 @@ sum .req r3 | |||
87 | b .Ldone | 87 | b .Ldone |
88 | 88 | ||
89 | FN_ENTRY | 89 | FN_ENTRY |
90 | mov ip, sp | ||
91 | save_regs | 90 | save_regs |
92 | sub fp, ip, #4 | ||
93 | 91 | ||
94 | cmp len, #8 @ Ensure that we have at least | 92 | cmp len, #8 @ Ensure that we have at least |
95 | blo .Lless8 @ 8 bytes to copy. | 93 | blo .Lless8 @ 8 bytes to copy. |
@@ -163,7 +161,7 @@ FN_ENTRY | |||
163 | ldr sum, [sp, #0] @ dst | 161 | ldr sum, [sp, #0] @ dst |
164 | tst sum, #1 | 162 | tst sum, #1 |
165 | movne r0, r0, ror #8 | 163 | movne r0, r0, ror #8 |
166 | load_regs ea | 164 | load_regs |
167 | 165 | ||
168 | .Lsrc_not_aligned: | 166 | .Lsrc_not_aligned: |
169 | adc sum, sum, #0 @ include C from dst alignment | 167 | adc sum, sum, #0 @ include C from dst alignment |
diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S index 333bca292de9..c3b93e22ea25 100644 --- a/arch/arm/lib/csumpartialcopyuser.S +++ b/arch/arm/lib/csumpartialcopyuser.S | |||
@@ -18,11 +18,13 @@ | |||
18 | .text | 18 | .text |
19 | 19 | ||
20 | .macro save_regs | 20 | .macro save_regs |
21 | mov ip, sp | ||
21 | stmfd sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc} | 22 | stmfd sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc} |
23 | sub fp, ip, #4 | ||
22 | .endm | 24 | .endm |
23 | 25 | ||
24 | .macro load_regs,flags | 26 | .macro load_regs |
25 | ldm\flags fp, {r1, r2, r4-r8, fp, sp, pc} | 27 | ldmfd sp, {r1, r2, r4-r8, fp, sp, pc} |
26 | .endm | 28 | .endm |
27 | 29 | ||
28 | .macro load1b, reg1 | 30 | .macro load1b, reg1 |
@@ -100,5 +102,5 @@ | |||
100 | 6002: teq r2, r1 | 102 | 6002: teq r2, r1 |
101 | strneb r0, [r1], #1 | 103 | strneb r0, [r1], #1 |
102 | bne 6002b | 104 | bne 6002b |
103 | load_regs ea | 105 | load_regs |
104 | .previous | 106 | .previous |