diff options
-rw-r--r-- | arch/sparc/kernel/traps_64.c | 12 | ||||
-rw-r--r-- | arch/sparc/math-emu/math_64.c | 20 |
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 | ||
2057 | extern int do_mathemu(struct pt_regs *, struct fpustate *); | 2057 | extern int do_mathemu(struct pt_regs *, struct fpustate *, bool); |
2058 | 2058 | ||
2059 | void do_fpother(struct pt_regs *regs) | 2059 | void 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 | ||
166 | int do_mathemu(struct pt_regs *regs, struct fpustate *f) | 166 | int 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) { |