aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-05-25 03:31:56 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-25 03:31:56 -0400
commit456d3d42460c1fc20ba0d27442443fcd63aaac35 (patch)
tree2bdd7021420f845f3c775e91ccc91aa791ef6c45 /arch/sparc
parent07acfc2a9349a8ce45b236c2624dad452001966b (diff)
sparc64: Fix several bugs in quad floating point emulation.
UltraSPARC-T2 and later do not use the fp_exception_other trap and do not set the floating point trap type field in the %fsr at all when you try to execute an unimplemented FPU operation. Instead, it uses the illegal_instruction trap and it leaves the floating point trap type field clear. So we should not validate the %fsr trap type field when do_mathemu() is invoked from the illegal instruction handler. Also, the floating point trap type field is 3 bits, not 4 bits. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/kernel/traps_64.c12
-rw-r--r--arch/sparc/math-emu/math_64.c20
2 files changed, 21 insertions, 11 deletions
diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c
index c72fdf55e1c1..3b05e6697710 100644
--- a/arch/sparc/kernel/traps_64.c
+++ b/arch/sparc/kernel/traps_64.c
@@ -2054,7 +2054,7 @@ void do_fpieee(struct pt_regs *regs)
2054 do_fpe_common(regs); 2054 do_fpe_common(regs);
2055} 2055}
2056 2056
2057extern int do_mathemu(struct pt_regs *, struct fpustate *); 2057extern int do_mathemu(struct pt_regs *, struct fpustate *, bool);
2058 2058
2059void do_fpother(struct pt_regs *regs) 2059void do_fpother(struct pt_regs *regs)
2060{ 2060{
@@ -2068,7 +2068,7 @@ void do_fpother(struct pt_regs *regs)
2068 switch ((current_thread_info()->xfsr[0] & 0x1c000)) { 2068 switch ((current_thread_info()->xfsr[0] & 0x1c000)) {
2069 case (2 << 14): /* unfinished_FPop */ 2069 case (2 << 14): /* unfinished_FPop */
2070 case (3 << 14): /* unimplemented_FPop */ 2070 case (3 << 14): /* unimplemented_FPop */
2071 ret = do_mathemu(regs, f); 2071 ret = do_mathemu(regs, f, false);
2072 break; 2072 break;
2073 } 2073 }
2074 if (ret) 2074 if (ret)
@@ -2308,10 +2308,12 @@ void do_illegal_instruction(struct pt_regs *regs)
2308 } else { 2308 } else {
2309 struct fpustate *f = FPUSTATE; 2309 struct fpustate *f = FPUSTATE;
2310 2310
2311 /* XXX maybe verify XFSR bits like 2311 /* On UltraSPARC T2 and later, FPU insns which
2312 * XXX do_fpother() does? 2312 * are not implemented in HW signal an illegal
2313 * instruction trap and do not set the FP Trap
2314 * Trap in the %fsr to unimplemented_FPop.
2313 */ 2315 */
2314 if (do_mathemu(regs, f)) 2316 if (do_mathemu(regs, f, true))
2315 return; 2317 return;
2316 } 2318 }
2317 } 2319 }
diff --git a/arch/sparc/math-emu/math_64.c b/arch/sparc/math-emu/math_64.c
index 2bbe2f28ad23..1704068da928 100644
--- a/arch/sparc/math-emu/math_64.c
+++ b/arch/sparc/math-emu/math_64.c
@@ -163,7 +163,7 @@ typedef union {
163 u64 q[2]; 163 u64 q[2];
164} *argp; 164} *argp;
165 165
166int do_mathemu(struct pt_regs *regs, struct fpustate *f) 166int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap)
167{ 167{
168 unsigned long pc = regs->tpc; 168 unsigned long pc = regs->tpc;
169 unsigned long tstate = regs->tstate; 169 unsigned long tstate = regs->tstate;
@@ -218,7 +218,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
218 case FSQRTS: { 218 case FSQRTS: {
219 unsigned long x = current_thread_info()->xfsr[0]; 219 unsigned long x = current_thread_info()->xfsr[0];
220 220
221 x = (x >> 14) & 0xf; 221 x = (x >> 14) & 0x7;
222 TYPE(x,1,1,1,1,0,0); 222 TYPE(x,1,1,1,1,0,0);
223 break; 223 break;
224 } 224 }
@@ -226,7 +226,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
226 case FSQRTD: { 226 case FSQRTD: {
227 unsigned long x = current_thread_info()->xfsr[0]; 227 unsigned long x = current_thread_info()->xfsr[0];
228 228
229 x = (x >> 14) & 0xf; 229 x = (x >> 14) & 0x7;
230 TYPE(x,2,1,2,1,0,0); 230 TYPE(x,2,1,2,1,0,0);
231 break; 231 break;
232 } 232 }
@@ -357,9 +357,17 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
357 if (type) { 357 if (type) {
358 argp rs1 = NULL, rs2 = NULL, rd = NULL; 358 argp rs1 = NULL, rs2 = NULL, rd = NULL;
359 359
360 freg = (current_thread_info()->xfsr[0] >> 14) & 0xf; 360 /* Starting with UltraSPARC-T2, the cpu does not set the FP Trap
361 if (freg != (type >> 9)) 361 * Type field in the %fsr to unimplemented_FPop. Nor does it
362 goto err; 362 * use the fp_exception_other trap. Instead it signals an
363 * illegal instruction and leaves the FP trap type field of
364 * the %fsr unchanged.
365 */
366 if (!illegal_insn_trap) {
367 int ftt = (current_thread_info()->xfsr[0] >> 14) & 0x7;
368 if (ftt != (type >> 9))
369 goto err;
370 }
363 current_thread_info()->xfsr[0] &= ~0x1c000; 371 current_thread_info()->xfsr[0] &= ~0x1c000;
364 freg = ((insn >> 14) & 0x1f); 372 freg = ((insn >> 14) & 0x1f);
365 switch (type & 0x3) { 373 switch (type & 0x3) {