MIPS: Clear upper bits of FP registers on emulator writes
authorPaul Burton <paul.burton@imgtec.com>
Mon, 27 Jan 2014 17:14:47 +0000 (17:14 +0000)
committerRalf Baechle <ralf@linux-mips.org>
Wed, 26 Mar 2014 22:09:10 +0000 (23:09 +0100)
The upper bits of an FP register are architecturally defined as
unpredictable following an instructions which only writes the lower
bits. The prior behaviour of the kernel is to leave them unmodified.
This patch modifies that to clear the upper bits to zero. This is what
the MSA architecture reference manual specifies should happen for its
wider registers and is still permissible for scalar FP instructions
given the bits unpredictability there.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: sergei.shtylyov@cogentembedded.com
Patchwork: https://patchwork.linux-mips.org/patch/6435/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/math-emu/cp1emu.c

index 196cf1ab65afc17e7537842e08b833d9801b421a..71a697c9d385b855fda6629a2bb786be5d1e4b1a 100644 (file)
@@ -884,20 +884,35 @@ static inline int cop1_64bit(struct pt_regs *xcp)
 } while (0)
 
 #define SITOREG(si, x) do {                                            \
-       if (cop1_64bit(xcp))                                            \
+       if (cop1_64bit(xcp)) {                                          \
+               unsigned i;                                             \
                set_fpr32(&ctx->fpr[x], 0, si);                         \
-       else                                                            \
+               for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val32); i++)     \
+                       set_fpr32(&ctx->fpr[x], i, 0);                  \
+       } else {                                                        \
                set_fpr32(&ctx->fpr[(x) & ~1], (x) & 1, si);            \
+       }                                                               \
 } while (0)
 
 #define SIFROMHREG(si, x)      ((si) = get_fpr32(&ctx->fpr[x], 1))
-#define SITOHREG(si, x)                set_fpr32(&ctx->fpr[x], 1, si)
+
+#define SITOHREG(si, x) do {                                           \
+       unsigned i;                                                     \
+       set_fpr32(&ctx->fpr[x], 1, si);                                 \
+       for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++)             \
+               set_fpr32(&ctx->fpr[x], i, 0);                          \
+} while (0)
 
 #define DIFROMREG(di, x) \
        ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0))
 
-#define DITOREG(di, x) \
-       set_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0, di)
+#define DITOREG(di, x) do {                                            \
+       unsigned fpr, i;                                                \
+       fpr = (x) & ~(cop1_64bit(xcp) == 0);                            \
+       set_fpr64(&ctx->fpr[fpr], 0, di);                               \
+       for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val64); i++)             \
+               set_fpr64(&ctx->fpr[fpr], i, 0);                        \
+} while (0)
 
 #define SPFROMREG(sp, x) SIFROMREG((sp).bits, x)
 #define SPTOREG(sp, x) SITOREG((sp).bits, x)