]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.32.17/mips-fpu-emulator-allow-cause-bits-of-fcsr-to-be-writeable-by-ctc1.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 2.6.32.17 / mips-fpu-emulator-allow-cause-bits-of-fcsr-to-be-writeable-by-ctc1.patch
1 From 95e8f634d7a3ea5af40ec3fa42c8a152fd3a0624 Mon Sep 17 00:00:00 2001
2 From: Shane McDonald <mcdonald.shane@gmail.com>
3 Date: Thu, 6 May 2010 23:26:57 -0600
4 Subject: MIPS FPU emulator: allow Cause bits of FCSR to be writeable by ctc1
5
6 From: Shane McDonald <mcdonald.shane@gmail.com>
7
8 commit 95e8f634d7a3ea5af40ec3fa42c8a152fd3a0624 upstream.
9
10 In the FPU emulator code of the MIPS, the Cause bits of the FCSR register
11 are not currently writeable by the ctc1 instruction. In odd corner cases,
12 this can cause problems. For example, a case existed where a divide-by-zero
13 exception was generated by the FPU, and the signal handler attempted to
14 restore the FPU registers to their state before the exception occurred. In
15 this particular setup, writing the old value to the FCSR register would
16 cause another divide-by-zero exception to occur immediately. The solution
17 is to change the ctc1 instruction emulator code to allow the Cause bits of
18 the FCSR register to be writeable. This is the behaviour of the hardware
19 that the code is emulating.
20
21 This problem was found by Shane McDonald, but the credit for the fix goes
22 to Kevin Kissell. In Kevin's words:
23
24 I submit that the bug is indeed in that ctc_op: case of the emulator. The
25 Cause bits (17:12) are supposed to be writable by that instruction, but the
26 CTC1 emulation won't let them be updated by the instruction. I think that
27 actually if you just completely removed lines 387-388 [...] things would
28 work a good deal better. At least, it would be a more accurate emulation of
29 the architecturally defined FPU. If I wanted to be really, really pedantic
30 (which I sometimes do), I'd also protect the reserved bits that aren't
31 necessarily writable.
32
33 Signed-off-by: Shane McDonald <mcdonald.shane@gmail.com>
34 To: anemo@mba.ocn.ne.jp
35 To: kevink@paralogos.com
36 To: sshtylyov@mvista.com
37 Patchwork: http://patchwork.linux-mips.org/patch/1205/
38 Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
39 Cc: Ben Hutchings <ben@decadent.org.uk>
40 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
41
42 ---
43
44 ---
45 arch/mips/include/asm/mipsregs.h | 9 ++++++++-
46 arch/mips/math-emu/cp1emu.c | 15 +++++++++++----
47 2 files changed, 19 insertions(+), 5 deletions(-)
48
49 --- a/arch/mips/include/asm/mipsregs.h
50 +++ b/arch/mips/include/asm/mipsregs.h
51 @@ -135,6 +135,12 @@
52 #define FPU_CSR_COND7 0x80000000 /* $fcc7 */
53
54 /*
55 + * Bits 18 - 20 of the FPU Status Register will be read as 0,
56 + * and should be written as zero.
57 + */
58 +#define FPU_CSR_RSVD 0x001c0000
59 +
60 +/*
61 * X the exception cause indicator
62 * E the exception enable
63 * S the sticky/flag bit
64 @@ -161,7 +167,8 @@
65 #define FPU_CSR_UDF_S 0x00000008
66 #define FPU_CSR_INE_S 0x00000004
67
68 -/* rounding mode */
69 +/* Bits 0 and 1 of FPU Status Register specify the rounding mode */
70 +#define FPU_CSR_RM 0x00000003
71 #define FPU_CSR_RN 0x0 /* nearest */
72 #define FPU_CSR_RZ 0x1 /* towards zero */
73 #define FPU_CSR_RU 0x2 /* towards +Infinity */
74 --- a/arch/mips/math-emu/cp1emu.c
75 +++ b/arch/mips/math-emu/cp1emu.c
76 @@ -75,6 +75,9 @@ struct mips_fpu_emulator_stats fpuemusta
77 #define FPCREG_RID 0 /* $0 = revision id */
78 #define FPCREG_CSR 31 /* $31 = csr */
79
80 +/* Determine rounding mode from the RM bits of the FCSR */
81 +#define modeindex(v) ((v) & FPU_CSR_RM)
82 +
83 /* Convert Mips rounding mode (0..3) to IEEE library modes. */
84 static const unsigned char ieee_rm[4] = {
85 [FPU_CSR_RN] = IEEE754_RN,
86 @@ -381,10 +384,14 @@ static int cop1Emulate(struct pt_regs *x
87 (void *) (xcp->cp0_epc),
88 MIPSInst_RT(ir), value);
89 #endif
90 - value &= (FPU_CSR_FLUSH | FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03);
91 - ctx->fcr31 &= ~(FPU_CSR_FLUSH | FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03);
92 - /* convert to ieee library modes */
93 - ctx->fcr31 |= (value & ~0x3) | ieee_rm[value & 0x3];
94 +
95 + /*
96 + * Don't write reserved bits,
97 + * and convert to ieee library modes
98 + */
99 + ctx->fcr31 = (value &
100 + ~(FPU_CSR_RSVD | FPU_CSR_RM)) |
101 + ieee_rm[modeindex(value)];
102 }
103 if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
104 return SIGFPE;