diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2016-03-10 03:52:55 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2016-03-10 08:35:42 -0500 |
commit | e370e4769463a65dcf8806fa26d2874e0542ac41 (patch) | |
tree | 29ab4542734a87a38ac31d709e7c5507661e44eb | |
parent | 8f100bb1ff27873dd71f636da670e503b9ade3c6 (diff) |
s390: fix floating pointer register corruption (again)
There is a tricky interaction between the machine check handler
and the critical sections of load_fpu_regs and save_fpu_regs
functions. If the machine check interrupts one of the two
functions the critical section cleanup will complete the function
before the machine check handler s390_do_machine_check is called.
Trouble is that the machine check handler needs to validate the
floating point registers *before* and not *after* the completion
of load_fpu_regs/save_fpu_regs.
The simplest solution is to rewind the PSW to the start of the
load_fpu_regs/save_fpu_regs and retry the function after the
return from the machine check handler.
Tested-by: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: <stable@vger.kernel.org> # 4.3+
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/kernel/entry.S | 106 |
1 files changed, 2 insertions, 104 deletions
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 4ba688c9d5a6..2d47f9cfcb36 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -1200,114 +1200,12 @@ cleanup_critical: | |||
1200 | .quad .Lpsw_idle_lpsw | 1200 | .quad .Lpsw_idle_lpsw |
1201 | 1201 | ||
1202 | .Lcleanup_save_fpu_regs: | 1202 | .Lcleanup_save_fpu_regs: |
1203 | TSTMSK __LC_CPU_FLAGS,_CIF_FPU | 1203 | larl %r9,save_fpu_regs |
1204 | bor %r14 | ||
1205 | clg %r9,BASED(.Lcleanup_save_fpu_regs_done) | ||
1206 | jhe 5f | ||
1207 | clg %r9,BASED(.Lcleanup_save_fpu_regs_fp) | ||
1208 | jhe 4f | ||
1209 | clg %r9,BASED(.Lcleanup_save_fpu_regs_vx_high) | ||
1210 | jhe 3f | ||
1211 | clg %r9,BASED(.Lcleanup_save_fpu_regs_vx_low) | ||
1212 | jhe 2f | ||
1213 | clg %r9,BASED(.Lcleanup_save_fpu_fpc_end) | ||
1214 | jhe 1f | ||
1215 | lg %r2,__LC_CURRENT | ||
1216 | aghi %r2,__TASK_thread | ||
1217 | 0: # Store floating-point controls | ||
1218 | stfpc __THREAD_FPU_fpc(%r2) | ||
1219 | 1: # Load register save area and check if VX is active | ||
1220 | lg %r3,__THREAD_FPU_regs(%r2) | ||
1221 | TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX | ||
1222 | jz 4f # no VX -> store FP regs | ||
1223 | 2: # Store vector registers (V0-V15) | ||
1224 | VSTM %v0,%v15,0,%r3 # vstm 0,15,0(3) | ||
1225 | 3: # Store vector registers (V16-V31) | ||
1226 | VSTM %v16,%v31,256,%r3 # vstm 16,31,256(3) | ||
1227 | j 5f # -> done, set CIF_FPU flag | ||
1228 | 4: # Store floating-point registers | ||
1229 | std 0,0(%r3) | ||
1230 | std 1,8(%r3) | ||
1231 | std 2,16(%r3) | ||
1232 | std 3,24(%r3) | ||
1233 | std 4,32(%r3) | ||
1234 | std 5,40(%r3) | ||
1235 | std 6,48(%r3) | ||
1236 | std 7,56(%r3) | ||
1237 | std 8,64(%r3) | ||
1238 | std 9,72(%r3) | ||
1239 | std 10,80(%r3) | ||
1240 | std 11,88(%r3) | ||
1241 | std 12,96(%r3) | ||
1242 | std 13,104(%r3) | ||
1243 | std 14,112(%r3) | ||
1244 | std 15,120(%r3) | ||
1245 | 5: # Set CIF_FPU flag | ||
1246 | oi __LC_CPU_FLAGS+7,_CIF_FPU | ||
1247 | lg %r9,48(%r11) # return from save_fpu_regs | ||
1248 | br %r14 | 1204 | br %r14 |
1249 | .Lcleanup_save_fpu_fpc_end: | ||
1250 | .quad .Lsave_fpu_regs_fpc_end | ||
1251 | .Lcleanup_save_fpu_regs_vx_low: | ||
1252 | .quad .Lsave_fpu_regs_vx_low | ||
1253 | .Lcleanup_save_fpu_regs_vx_high: | ||
1254 | .quad .Lsave_fpu_regs_vx_high | ||
1255 | .Lcleanup_save_fpu_regs_fp: | ||
1256 | .quad .Lsave_fpu_regs_fp | ||
1257 | .Lcleanup_save_fpu_regs_done: | ||
1258 | .quad .Lsave_fpu_regs_done | ||
1259 | 1205 | ||
1260 | .Lcleanup_load_fpu_regs: | 1206 | .Lcleanup_load_fpu_regs: |
1261 | TSTMSK __LC_CPU_FLAGS,_CIF_FPU | 1207 | larl %r9,load_fpu_regs |
1262 | bnor %r14 | ||
1263 | clg %r9,BASED(.Lcleanup_load_fpu_regs_done) | ||
1264 | jhe 1f | ||
1265 | clg %r9,BASED(.Lcleanup_load_fpu_regs_fp) | ||
1266 | jhe 2f | ||
1267 | clg %r9,BASED(.Lcleanup_load_fpu_regs_vx_high) | ||
1268 | jhe 3f | ||
1269 | clg %r9,BASED(.Lcleanup_load_fpu_regs_vx) | ||
1270 | jhe 4f | ||
1271 | lg %r4,__LC_CURRENT | ||
1272 | aghi %r4,__TASK_thread | ||
1273 | lfpc __THREAD_FPU_fpc(%r4) | ||
1274 | TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX | ||
1275 | lg %r4,__THREAD_FPU_regs(%r4) # %r4 <- reg save area | ||
1276 | jz 2f # -> no VX, load FP regs | ||
1277 | 4: # Load V0 ..V15 registers | ||
1278 | VLM %v0,%v15,0,%r4 | ||
1279 | 3: # Load V16..V31 registers | ||
1280 | VLM %v16,%v31,256,%r4 | ||
1281 | j 1f | ||
1282 | 2: # Load floating-point registers | ||
1283 | ld 0,0(%r4) | ||
1284 | ld 1,8(%r4) | ||
1285 | ld 2,16(%r4) | ||
1286 | ld 3,24(%r4) | ||
1287 | ld 4,32(%r4) | ||
1288 | ld 5,40(%r4) | ||
1289 | ld 6,48(%r4) | ||
1290 | ld 7,56(%r4) | ||
1291 | ld 8,64(%r4) | ||
1292 | ld 9,72(%r4) | ||
1293 | ld 10,80(%r4) | ||
1294 | ld 11,88(%r4) | ||
1295 | ld 12,96(%r4) | ||
1296 | ld 13,104(%r4) | ||
1297 | ld 14,112(%r4) | ||
1298 | ld 15,120(%r4) | ||
1299 | 1: # Clear CIF_FPU bit | ||
1300 | ni __LC_CPU_FLAGS+7,255-_CIF_FPU | ||
1301 | lg %r9,48(%r11) # return from load_fpu_regs | ||
1302 | br %r14 | 1208 | br %r14 |
1303 | .Lcleanup_load_fpu_regs_vx: | ||
1304 | .quad .Lload_fpu_regs_vx | ||
1305 | .Lcleanup_load_fpu_regs_vx_high: | ||
1306 | .quad .Lload_fpu_regs_vx_high | ||
1307 | .Lcleanup_load_fpu_regs_fp: | ||
1308 | .quad .Lload_fpu_regs_fp | ||
1309 | .Lcleanup_load_fpu_regs_done: | ||
1310 | .quad .Lload_fpu_regs_done | ||
1311 | 1209 | ||
1312 | /* | 1210 | /* |
1313 | * Integer constants | 1211 | * Integer constants |