diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-10-15 10:08:34 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-10-24 11:17:11 -0400 |
commit | 4725c86055f5bbdcdfe47199c0715881893a2c79 (patch) | |
tree | e201bd8d8a11e58117e9ecf360f3fab43c6267e9 /arch/s390/kernel/process.c | |
parent | 01a7cfa24afd8e18ce691d3c2f1e1f093cf3a900 (diff) |
s390: fix save and restore of the floating-point-control register
The FPC_VALID_MASK has been used to check the validity of the value
to be loaded into the floating-point-control register. With the
introduction of the floating-point extension facility and the
decimal-floating-point additional bits have been defined which need
to be checked in a non straight forward way. So far these bits have
been ignored which can cause an incorrect results for decimal-
floating-point operations, e.g. an incorrect rounding mode to be
set after signal return.
The static check with the FPC_VALID_MASK is replaced with a trial
load of the floating-point-control value, see test_fp_ctl.
In addition an information leak with the padding word between the
floating-point-control word and the floating-point registers in
the s390_fp_regs is fixed.
Reported-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/process.c')
-rw-r--r-- | arch/s390/kernel/process.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index e1cdd31acabb..7ed0d4e2a435 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
@@ -165,7 +165,8 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | |||
165 | * save fprs to current->thread.fp_regs to merge them with | 165 | * save fprs to current->thread.fp_regs to merge them with |
166 | * the emulated registers and then copy the result to the child. | 166 | * the emulated registers and then copy the result to the child. |
167 | */ | 167 | */ |
168 | save_fp_regs(¤t->thread.fp_regs); | 168 | save_fp_ctl(¤t->thread.fp_regs.fpc); |
169 | save_fp_regs(current->thread.fp_regs.fprs); | ||
169 | memcpy(&p->thread.fp_regs, ¤t->thread.fp_regs, | 170 | memcpy(&p->thread.fp_regs, ¤t->thread.fp_regs, |
170 | sizeof(s390_fp_regs)); | 171 | sizeof(s390_fp_regs)); |
171 | /* Set a new TLS ? */ | 172 | /* Set a new TLS ? */ |
@@ -173,7 +174,9 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | |||
173 | p->thread.acrs[0] = frame->childregs.gprs[6]; | 174 | p->thread.acrs[0] = frame->childregs.gprs[6]; |
174 | #else /* CONFIG_64BIT */ | 175 | #else /* CONFIG_64BIT */ |
175 | /* Save the fpu registers to new thread structure. */ | 176 | /* Save the fpu registers to new thread structure. */ |
176 | save_fp_regs(&p->thread.fp_regs); | 177 | save_fp_ctl(&p->thread.fp_regs.fpc); |
178 | save_fp_regs(p->thread.fp_regs.fprs); | ||
179 | p->thread.fp_regs.pad = 0; | ||
177 | /* Set a new TLS ? */ | 180 | /* Set a new TLS ? */ |
178 | if (clone_flags & CLONE_SETTLS) { | 181 | if (clone_flags & CLONE_SETTLS) { |
179 | unsigned long tls = frame->childregs.gprs[6]; | 182 | unsigned long tls = frame->childregs.gprs[6]; |
@@ -205,10 +208,12 @@ int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs) | |||
205 | * save fprs to current->thread.fp_regs to merge them with | 208 | * save fprs to current->thread.fp_regs to merge them with |
206 | * the emulated registers and then copy the result to the dump. | 209 | * the emulated registers and then copy the result to the dump. |
207 | */ | 210 | */ |
208 | save_fp_regs(¤t->thread.fp_regs); | 211 | save_fp_ctl(¤t->thread.fp_regs.fpc); |
212 | save_fp_regs(current->thread.fp_regs.fprs); | ||
209 | memcpy(fpregs, ¤t->thread.fp_regs, sizeof(s390_fp_regs)); | 213 | memcpy(fpregs, ¤t->thread.fp_regs, sizeof(s390_fp_regs)); |
210 | #else /* CONFIG_64BIT */ | 214 | #else /* CONFIG_64BIT */ |
211 | save_fp_regs(fpregs); | 215 | save_fp_ctl(&fpregs->fpc); |
216 | save_fp_regs(fpregs->fprs); | ||
212 | #endif /* CONFIG_64BIT */ | 217 | #endif /* CONFIG_64BIT */ |
213 | return 1; | 218 | return 1; |
214 | } | 219 | } |