aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/lib/U3memcpy.S
diff options
context:
space:
mode:
authorRob Gardner <rob.gardner@oracle.com>2015-12-23 01:24:49 -0500
committerDavid S. Miller <davem@davemloft.net>2015-12-24 12:13:18 -0500
commita7c5724b5c17775ca8ea2fd9906d8a7e37337cce (patch)
tree802877bf40b98d95256551b97ac42492705291d3 /arch/sparc/lib/U3memcpy.S
parent833526941f5945cf0b22a595bb8f3525b512f654 (diff)
sparc64: fix FP corruption in user copy functions
Short story: Exception handlers used by some copy_to_user() and copy_from_user() functions do not diligently clean up floating point register usage, and this can result in a user process seeing invalid values in floating point registers. This sometimes makes the process fail. Long story: Several cpu-specific (NG4, NG2, U1, U3) memcpy functions use floating point registers and VIS alignaddr/faligndata to accelerate data copying when source and dest addresses don't align well. Linux uses a lazy scheme for saving floating point registers; It is not done upon entering the kernel since it's a very expensive operation. Rather, it is done only when needed. If the kernel ends up not using FP regs during the course of some trap or system call, then it can return to user space without saving or restoring them. The various memcpy functions begin their FP code with VISEntry (or a variation thereof), which saves the FP regs. They conclude their FP code with VISExit (or a variation) which essentially marks the FP regs "clean", ie, they contain no unsaved values. fprs.FPRS_FEF is turned off so that a lazy restore will be triggered when/if the user process accesses floating point regs again. The bug is that the user copy variants of memcpy, copy_from_user() and copy_to_user(), employ an exception handling mechanism to detect faults when accessing user space addresses, and when this handler is invoked, an immediate return from the function is forced, and VISExit is not executed, thus leaving the fprs register in an indeterminate state, but often with fprs.FPRS_FEF set and one or more dirty bits. This results in a return to user space with invalid values in the FP regs, and since fprs.FPRS_FEF is on, no lazy restore occurs. This bug affects copy_to_user() and copy_from_user() for NG4, NG2, U3, and U1. All are fixed by using a new exception handler for those loads and stores that are done during the time between VISEnter and VISExit. n.b. In NG4memcpy, the problematic code can be triggered by a copy size greater than 128 bytes and an unaligned source address. This bug is known to be the cause of random user process memory corruptions while perf is running with the callgraph option (ie, perf record -g). This occurs because perf uses copy_from_user() to read user stacks, and may fault when it follows a stack frame pointer off to an invalid page. Validation checks on the stack address just obscure the underlying problem. Signed-off-by: Rob Gardner <rob.gardner@oracle.com> Signed-off-by: Dave Aldridge <david.j.aldridge@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/lib/U3memcpy.S')
-rw-r--r--arch/sparc/lib/U3memcpy.S86
1 files changed, 46 insertions, 40 deletions
diff --git a/arch/sparc/lib/U3memcpy.S b/arch/sparc/lib/U3memcpy.S
index 7cae9cc6a204..491ee69e4995 100644
--- a/arch/sparc/lib/U3memcpy.S
+++ b/arch/sparc/lib/U3memcpy.S
@@ -24,10 +24,16 @@
24#ifndef EX_LD 24#ifndef EX_LD
25#define EX_LD(x) x 25#define EX_LD(x) x
26#endif 26#endif
27#ifndef EX_LD_FP
28#define EX_LD_FP(x) x
29#endif
27 30
28#ifndef EX_ST 31#ifndef EX_ST
29#define EX_ST(x) x 32#define EX_ST(x) x
30#endif 33#endif
34#ifndef EX_ST_FP
35#define EX_ST_FP(x) x
36#endif
31 37
32#ifndef EX_RETVAL 38#ifndef EX_RETVAL
33#define EX_RETVAL(x) x 39#define EX_RETVAL(x) x
@@ -120,8 +126,8 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
120 and %g2, 0x38, %g2 126 and %g2, 0x38, %g2
121 127
1221: subcc %g1, 0x1, %g1 1281: subcc %g1, 0x1, %g1
123 EX_LD(LOAD(ldub, %o1 + 0x00, %o3)) 129 EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3))
124 EX_ST(STORE(stb, %o3, %o1 + GLOBAL_SPARE)) 130 EX_ST_FP(STORE(stb, %o3, %o1 + GLOBAL_SPARE))
125 bgu,pt %XCC, 1b 131 bgu,pt %XCC, 1b
126 add %o1, 0x1, %o1 132 add %o1, 0x1, %o1
127 133
@@ -132,20 +138,20 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
132 be,pt %icc, 3f 138 be,pt %icc, 3f
133 alignaddr %o1, %g0, %o1 139 alignaddr %o1, %g0, %o1
134 140
135 EX_LD(LOAD(ldd, %o1, %f4)) 141 EX_LD_FP(LOAD(ldd, %o1, %f4))
1361: EX_LD(LOAD(ldd, %o1 + 0x8, %f6)) 1421: EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6))
137 add %o1, 0x8, %o1 143 add %o1, 0x8, %o1
138 subcc %g2, 0x8, %g2 144 subcc %g2, 0x8, %g2
139 faligndata %f4, %f6, %f0 145 faligndata %f4, %f6, %f0
140 EX_ST(STORE(std, %f0, %o0)) 146 EX_ST_FP(STORE(std, %f0, %o0))
141 be,pn %icc, 3f 147 be,pn %icc, 3f
142 add %o0, 0x8, %o0 148 add %o0, 0x8, %o0
143 149
144 EX_LD(LOAD(ldd, %o1 + 0x8, %f4)) 150 EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4))
145 add %o1, 0x8, %o1 151 add %o1, 0x8, %o1
146 subcc %g2, 0x8, %g2 152 subcc %g2, 0x8, %g2
147 faligndata %f6, %f4, %f2 153 faligndata %f6, %f4, %f2
148 EX_ST(STORE(std, %f2, %o0)) 154 EX_ST_FP(STORE(std, %f2, %o0))
149 bne,pt %icc, 1b 155 bne,pt %icc, 1b
150 add %o0, 0x8, %o0 156 add %o0, 0x8, %o0
151 157
@@ -155,25 +161,25 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
155 LOAD(prefetch, %o1 + 0x080, #one_read) 161 LOAD(prefetch, %o1 + 0x080, #one_read)
156 LOAD(prefetch, %o1 + 0x0c0, #one_read) 162 LOAD(prefetch, %o1 + 0x0c0, #one_read)
157 LOAD(prefetch, %o1 + 0x100, #one_read) 163 LOAD(prefetch, %o1 + 0x100, #one_read)
158 EX_LD(LOAD(ldd, %o1 + 0x000, %f0)) 164 EX_LD_FP(LOAD(ldd, %o1 + 0x000, %f0))
159 LOAD(prefetch, %o1 + 0x140, #one_read) 165 LOAD(prefetch, %o1 + 0x140, #one_read)
160 EX_LD(LOAD(ldd, %o1 + 0x008, %f2)) 166 EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
161 LOAD(prefetch, %o1 + 0x180, #one_read) 167 LOAD(prefetch, %o1 + 0x180, #one_read)
162 EX_LD(LOAD(ldd, %o1 + 0x010, %f4)) 168 EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
163 LOAD(prefetch, %o1 + 0x1c0, #one_read) 169 LOAD(prefetch, %o1 + 0x1c0, #one_read)
164 faligndata %f0, %f2, %f16 170 faligndata %f0, %f2, %f16
165 EX_LD(LOAD(ldd, %o1 + 0x018, %f6)) 171 EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
166 faligndata %f2, %f4, %f18 172 faligndata %f2, %f4, %f18
167 EX_LD(LOAD(ldd, %o1 + 0x020, %f8)) 173 EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
168 faligndata %f4, %f6, %f20 174 faligndata %f4, %f6, %f20
169 EX_LD(LOAD(ldd, %o1 + 0x028, %f10)) 175 EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
170 faligndata %f6, %f8, %f22 176 faligndata %f6, %f8, %f22
171 177
172 EX_LD(LOAD(ldd, %o1 + 0x030, %f12)) 178 EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
173 faligndata %f8, %f10, %f24 179 faligndata %f8, %f10, %f24
174 EX_LD(LOAD(ldd, %o1 + 0x038, %f14)) 180 EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
175 faligndata %f10, %f12, %f26 181 faligndata %f10, %f12, %f26
176 EX_LD(LOAD(ldd, %o1 + 0x040, %f0)) 182 EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
177 183
178 subcc GLOBAL_SPARE, 0x80, GLOBAL_SPARE 184 subcc GLOBAL_SPARE, 0x80, GLOBAL_SPARE
179 add %o1, 0x40, %o1 185 add %o1, 0x40, %o1
@@ -184,26 +190,26 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
184 190
185 .align 64 191 .align 64
1861: 1921:
187 EX_LD(LOAD(ldd, %o1 + 0x008, %f2)) 193 EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
188 faligndata %f12, %f14, %f28 194 faligndata %f12, %f14, %f28
189 EX_LD(LOAD(ldd, %o1 + 0x010, %f4)) 195 EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
190 faligndata %f14, %f0, %f30 196 faligndata %f14, %f0, %f30
191 EX_ST(STORE_BLK(%f16, %o0)) 197 EX_ST_FP(STORE_BLK(%f16, %o0))
192 EX_LD(LOAD(ldd, %o1 + 0x018, %f6)) 198 EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
193 faligndata %f0, %f2, %f16 199 faligndata %f0, %f2, %f16
194 add %o0, 0x40, %o0 200 add %o0, 0x40, %o0
195 201
196 EX_LD(LOAD(ldd, %o1 + 0x020, %f8)) 202 EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
197 faligndata %f2, %f4, %f18 203 faligndata %f2, %f4, %f18
198 EX_LD(LOAD(ldd, %o1 + 0x028, %f10)) 204 EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
199 faligndata %f4, %f6, %f20 205 faligndata %f4, %f6, %f20
200 EX_LD(LOAD(ldd, %o1 + 0x030, %f12)) 206 EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
201 subcc %o3, 0x01, %o3 207 subcc %o3, 0x01, %o3
202 faligndata %f6, %f8, %f22 208 faligndata %f6, %f8, %f22
203 EX_LD(LOAD(ldd, %o1 + 0x038, %f14)) 209 EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
204 210
205 faligndata %f8, %f10, %f24 211 faligndata %f8, %f10, %f24
206 EX_LD(LOAD(ldd, %o1 + 0x040, %f0)) 212 EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
207 LOAD(prefetch, %o1 + 0x1c0, #one_read) 213 LOAD(prefetch, %o1 + 0x1c0, #one_read)
208 faligndata %f10, %f12, %f26 214 faligndata %f10, %f12, %f26
209 bg,pt %XCC, 1b 215 bg,pt %XCC, 1b
@@ -211,29 +217,29 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
211 217
212 /* Finally we copy the last full 64-byte block. */ 218 /* Finally we copy the last full 64-byte block. */
2132: 2192:
214 EX_LD(LOAD(ldd, %o1 + 0x008, %f2)) 220 EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
215 faligndata %f12, %f14, %f28 221 faligndata %f12, %f14, %f28
216 EX_LD(LOAD(ldd, %o1 + 0x010, %f4)) 222 EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
217 faligndata %f14, %f0, %f30 223 faligndata %f14, %f0, %f30
218 EX_ST(STORE_BLK(%f16, %o0)) 224 EX_ST_FP(STORE_BLK(%f16, %o0))
219 EX_LD(LOAD(ldd, %o1 + 0x018, %f6)) 225 EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
220 faligndata %f0, %f2, %f16 226 faligndata %f0, %f2, %f16
221 EX_LD(LOAD(ldd, %o1 + 0x020, %f8)) 227 EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
222 faligndata %f2, %f4, %f18 228 faligndata %f2, %f4, %f18
223 EX_LD(LOAD(ldd, %o1 + 0x028, %f10)) 229 EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
224 faligndata %f4, %f6, %f20 230 faligndata %f4, %f6, %f20
225 EX_LD(LOAD(ldd, %o1 + 0x030, %f12)) 231 EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
226 faligndata %f6, %f8, %f22 232 faligndata %f6, %f8, %f22
227 EX_LD(LOAD(ldd, %o1 + 0x038, %f14)) 233 EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
228 faligndata %f8, %f10, %f24 234 faligndata %f8, %f10, %f24
229 cmp %g1, 0 235 cmp %g1, 0
230 be,pt %XCC, 1f 236 be,pt %XCC, 1f
231 add %o0, 0x40, %o0 237 add %o0, 0x40, %o0
232 EX_LD(LOAD(ldd, %o1 + 0x040, %f0)) 238 EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
2331: faligndata %f10, %f12, %f26 2391: faligndata %f10, %f12, %f26
234 faligndata %f12, %f14, %f28 240 faligndata %f12, %f14, %f28
235 faligndata %f14, %f0, %f30 241 faligndata %f14, %f0, %f30
236 EX_ST(STORE_BLK(%f16, %o0)) 242 EX_ST_FP(STORE_BLK(%f16, %o0))
237 add %o0, 0x40, %o0 243 add %o0, 0x40, %o0
238 add %o1, 0x40, %o1 244 add %o1, 0x40, %o1
239 membar #Sync 245 membar #Sync
@@ -253,20 +259,20 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
253 259
254 sub %o2, %g2, %o2 260 sub %o2, %g2, %o2
255 be,a,pt %XCC, 1f 261 be,a,pt %XCC, 1f
256 EX_LD(LOAD(ldd, %o1 + 0x00, %f0)) 262 EX_LD_FP(LOAD(ldd, %o1 + 0x00, %f0))
257 263
2581: EX_LD(LOAD(ldd, %o1 + 0x08, %f2)) 2641: EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f2))
259 add %o1, 0x8, %o1 265 add %o1, 0x8, %o1
260 subcc %g2, 0x8, %g2 266 subcc %g2, 0x8, %g2
261 faligndata %f0, %f2, %f8 267 faligndata %f0, %f2, %f8
262 EX_ST(STORE(std, %f8, %o0)) 268 EX_ST_FP(STORE(std, %f8, %o0))
263 be,pn %XCC, 2f 269 be,pn %XCC, 2f
264 add %o0, 0x8, %o0 270 add %o0, 0x8, %o0
265 EX_LD(LOAD(ldd, %o1 + 0x08, %f0)) 271 EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f0))
266 add %o1, 0x8, %o1 272 add %o1, 0x8, %o1
267 subcc %g2, 0x8, %g2 273 subcc %g2, 0x8, %g2
268 faligndata %f2, %f0, %f8 274 faligndata %f2, %f0, %f8
269 EX_ST(STORE(std, %f8, %o0)) 275 EX_ST_FP(STORE(std, %f8, %o0))
270 bne,pn %XCC, 1b 276 bne,pn %XCC, 1b
271 add %o0, 0x8, %o0 277 add %o0, 0x8, %o0
272 278