aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2016-03-10 03:52:55 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-03-10 08:35:42 -0500
commite370e4769463a65dcf8806fa26d2874e0542ac41 (patch)
tree29ab4542734a87a38ac31d709e7c5507661e44eb
parent8f100bb1ff27873dd71f636da670e503b9ade3c6 (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.S106
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
12170: # Store floating-point controls
1218 stfpc __THREAD_FPU_fpc(%r2)
12191: # 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
12232: # Store vector registers (V0-V15)
1224 VSTM %v0,%v15,0,%r3 # vstm 0,15,0(3)
12253: # Store vector registers (V16-V31)
1226 VSTM %v16,%v31,256,%r3 # vstm 16,31,256(3)
1227 j 5f # -> done, set CIF_FPU flag
12284: # 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)
12455: # 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
12774: # Load V0 ..V15 registers
1278 VLM %v0,%v15,0,%r4
12793: # Load V16..V31 registers
1280 VLM %v16,%v31,256,%r4
1281 j 1f
12822: # 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)
12991: # 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