aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2013-11-22 08:12:07 -0500
committerRalf Baechle <ralf@linux-mips.org>2014-01-13 17:40:56 -0500
commit597ce1723e0fa0bdbe2ae4c94f18da6e29b92635 (patch)
tree21f67268915b8457dd305c6bcf7ac905772fd0ee
parent56a22d21bf9744315f56b2bbd6416170f27b7765 (diff)
MIPS: Support for 64-bit FP with O32 binaries
CPUs implementing MIPS32 R2 may include a 64-bit FPU, just as MIPS64 CPUs do. In order to preserve backwards compatibility a 64-bit FPU will act like a 32-bit FPU (by accessing doubles from the least significant 32 bits of an even-odd pair of FP registers) when the Status.FR bit is zero, again just like a mips64 CPU. The standard O32 ABI is defined expecting a 32-bit FPU, however recent toolchains support use of a 64-bit FPU from an O32 MIPS32 executable. When an ELF executable is built to use a 64-bit FPU a new flag (EF_MIPS_FP64) is set in the ELF header. With this patch the kernel will check the EF_MIPS_FP64 flag when executing an O32 binary, and set Status.FR accordingly. The addition of O32 64-bit FP support lessens the opportunity for optimisation in the FPU emulator, so a CONFIG_MIPS_O32_FP64_SUPPORT Kconfig option is introduced to allow this support to be disabled for those that don't require it. Inspired by an earlier patch by Leonid Yegoshin, but implemented more cleanly & correctly. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Cc: Paul Burton <paul.burton@imgtec.com> Patchwork: https://patchwork.linux-mips.org/patch/6154/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/Kconfig17
-rw-r--r--arch/mips/include/asm/asmmacro-32.h42
-rw-r--r--arch/mips/include/asm/asmmacro-64.h96
-rw-r--r--arch/mips/include/asm/asmmacro.h107
-rw-r--r--arch/mips/include/asm/elf.h31
-rw-r--r--arch/mips/include/asm/fpu.h91
-rw-r--r--arch/mips/include/asm/thread_info.h4
-rw-r--r--arch/mips/kernel/binfmt_elfo32.c14
-rw-r--r--arch/mips/kernel/cpu-probe.c2
-rw-r--r--arch/mips/kernel/process.c3
-rw-r--r--arch/mips/kernel/ptrace.c60
-rw-r--r--arch/mips/kernel/ptrace32.c53
-rw-r--r--arch/mips/kernel/r4k_fpu.S74
-rw-r--r--arch/mips/kernel/r4k_switch.S45
-rw-r--r--arch/mips/kernel/signal.c10
-rw-r--r--arch/mips/kernel/signal32.c10
-rw-r--r--arch/mips/kernel/traps.c10
-rw-r--r--arch/mips/math-emu/cp1emu.c10
-rw-r--r--arch/mips/math-emu/kernel_linkage.c6
19 files changed, 449 insertions, 236 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 650de3976e7a..c12d9c807d09 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2335,6 +2335,23 @@ config CC_STACKPROTECTOR
2335 2335
2336 This feature requires gcc version 4.2 or above. 2336 This feature requires gcc version 4.2 or above.
2337 2337
2338config MIPS_O32_FP64_SUPPORT
2339 bool "Support for O32 binaries using 64-bit FP"
2340 depends on 32BIT || MIPS32_O32
2341 default y
2342 help
2343 When this is enabled, the kernel will support use of 64-bit floating
2344 point registers with binaries using the O32 ABI along with the
2345 EF_MIPS_FP64 ELF header flag (typically built with -mfp64). On
2346 32-bit MIPS systems this support is at the cost of increasing the
2347 size and complexity of the compiled FPU emulator. Thus if you are
2348 running a MIPS32 system and know that none of your userland binaries
2349 will require 64-bit floating point, you may wish to reduce the size
2350 of your kernel & potentially improve FP emulation performance by
2351 saying N here.
2352
2353 If unsure, say Y.
2354
2338config USE_OF 2355config USE_OF
2339 bool 2356 bool
2340 select OF 2357 select OF
diff --git a/arch/mips/include/asm/asmmacro-32.h b/arch/mips/include/asm/asmmacro-32.h
index 2413afe21b33..70e1f176f123 100644
--- a/arch/mips/include/asm/asmmacro-32.h
+++ b/arch/mips/include/asm/asmmacro-32.h
@@ -12,27 +12,6 @@
12#include <asm/fpregdef.h> 12#include <asm/fpregdef.h>
13#include <asm/mipsregs.h> 13#include <asm/mipsregs.h>
14 14
15 .macro fpu_save_double thread status tmp1=t0
16 cfc1 \tmp1, fcr31
17 sdc1 $f0, THREAD_FPR0(\thread)
18 sdc1 $f2, THREAD_FPR2(\thread)
19 sdc1 $f4, THREAD_FPR4(\thread)
20 sdc1 $f6, THREAD_FPR6(\thread)
21 sdc1 $f8, THREAD_FPR8(\thread)
22 sdc1 $f10, THREAD_FPR10(\thread)
23 sdc1 $f12, THREAD_FPR12(\thread)
24 sdc1 $f14, THREAD_FPR14(\thread)
25 sdc1 $f16, THREAD_FPR16(\thread)
26 sdc1 $f18, THREAD_FPR18(\thread)
27 sdc1 $f20, THREAD_FPR20(\thread)
28 sdc1 $f22, THREAD_FPR22(\thread)
29 sdc1 $f24, THREAD_FPR24(\thread)
30 sdc1 $f26, THREAD_FPR26(\thread)
31 sdc1 $f28, THREAD_FPR28(\thread)
32 sdc1 $f30, THREAD_FPR30(\thread)
33 sw \tmp1, THREAD_FCR31(\thread)
34 .endm
35
36 .macro fpu_save_single thread tmp=t0 15 .macro fpu_save_single thread tmp=t0
37 cfc1 \tmp, fcr31 16 cfc1 \tmp, fcr31
38 swc1 $f0, THREAD_FPR0(\thread) 17 swc1 $f0, THREAD_FPR0(\thread)
@@ -70,27 +49,6 @@
70 sw \tmp, THREAD_FCR31(\thread) 49 sw \tmp, THREAD_FCR31(\thread)
71 .endm 50 .endm
72 51
73 .macro fpu_restore_double thread status tmp=t0
74 lw \tmp, THREAD_FCR31(\thread)
75 ldc1 $f0, THREAD_FPR0(\thread)
76 ldc1 $f2, THREAD_FPR2(\thread)
77 ldc1 $f4, THREAD_FPR4(\thread)
78 ldc1 $f6, THREAD_FPR6(\thread)
79 ldc1 $f8, THREAD_FPR8(\thread)
80 ldc1 $f10, THREAD_FPR10(\thread)
81 ldc1 $f12, THREAD_FPR12(\thread)
82 ldc1 $f14, THREAD_FPR14(\thread)
83 ldc1 $f16, THREAD_FPR16(\thread)
84 ldc1 $f18, THREAD_FPR18(\thread)
85 ldc1 $f20, THREAD_FPR20(\thread)
86 ldc1 $f22, THREAD_FPR22(\thread)
87 ldc1 $f24, THREAD_FPR24(\thread)
88 ldc1 $f26, THREAD_FPR26(\thread)
89 ldc1 $f28, THREAD_FPR28(\thread)
90 ldc1 $f30, THREAD_FPR30(\thread)
91 ctc1 \tmp, fcr31
92 .endm
93
94 .macro fpu_restore_single thread tmp=t0 52 .macro fpu_restore_single thread tmp=t0
95 lw \tmp, THREAD_FCR31(\thread) 53 lw \tmp, THREAD_FCR31(\thread)
96 lwc1 $f0, THREAD_FPR0(\thread) 54 lwc1 $f0, THREAD_FPR0(\thread)
diff --git a/arch/mips/include/asm/asmmacro-64.h b/arch/mips/include/asm/asmmacro-64.h
index 08a527dfe4a3..38ea609465b1 100644
--- a/arch/mips/include/asm/asmmacro-64.h
+++ b/arch/mips/include/asm/asmmacro-64.h
@@ -13,102 +13,6 @@
13#include <asm/fpregdef.h> 13#include <asm/fpregdef.h>
14#include <asm/mipsregs.h> 14#include <asm/mipsregs.h>
15 15
16 .macro fpu_save_16even thread tmp=t0
17 cfc1 \tmp, fcr31
18 sdc1 $f0, THREAD_FPR0(\thread)
19 sdc1 $f2, THREAD_FPR2(\thread)
20 sdc1 $f4, THREAD_FPR4(\thread)
21 sdc1 $f6, THREAD_FPR6(\thread)
22 sdc1 $f8, THREAD_FPR8(\thread)
23 sdc1 $f10, THREAD_FPR10(\thread)
24 sdc1 $f12, THREAD_FPR12(\thread)
25 sdc1 $f14, THREAD_FPR14(\thread)
26 sdc1 $f16, THREAD_FPR16(\thread)
27 sdc1 $f18, THREAD_FPR18(\thread)
28 sdc1 $f20, THREAD_FPR20(\thread)
29 sdc1 $f22, THREAD_FPR22(\thread)
30 sdc1 $f24, THREAD_FPR24(\thread)
31 sdc1 $f26, THREAD_FPR26(\thread)
32 sdc1 $f28, THREAD_FPR28(\thread)
33 sdc1 $f30, THREAD_FPR30(\thread)
34 sw \tmp, THREAD_FCR31(\thread)
35 .endm
36
37 .macro fpu_save_16odd thread
38 sdc1 $f1, THREAD_FPR1(\thread)
39 sdc1 $f3, THREAD_FPR3(\thread)
40 sdc1 $f5, THREAD_FPR5(\thread)
41 sdc1 $f7, THREAD_FPR7(\thread)
42 sdc1 $f9, THREAD_FPR9(\thread)
43 sdc1 $f11, THREAD_FPR11(\thread)
44 sdc1 $f13, THREAD_FPR13(\thread)
45 sdc1 $f15, THREAD_FPR15(\thread)
46 sdc1 $f17, THREAD_FPR17(\thread)
47 sdc1 $f19, THREAD_FPR19(\thread)
48 sdc1 $f21, THREAD_FPR21(\thread)
49 sdc1 $f23, THREAD_FPR23(\thread)
50 sdc1 $f25, THREAD_FPR25(\thread)
51 sdc1 $f27, THREAD_FPR27(\thread)
52 sdc1 $f29, THREAD_FPR29(\thread)
53 sdc1 $f31, THREAD_FPR31(\thread)
54 .endm
55
56 .macro fpu_save_double thread status tmp
57 sll \tmp, \status, 5
58 bgez \tmp, 2f
59 fpu_save_16odd \thread
602:
61 fpu_save_16even \thread \tmp
62 .endm
63
64 .macro fpu_restore_16even thread tmp=t0
65 lw \tmp, THREAD_FCR31(\thread)
66 ldc1 $f0, THREAD_FPR0(\thread)
67 ldc1 $f2, THREAD_FPR2(\thread)
68 ldc1 $f4, THREAD_FPR4(\thread)
69 ldc1 $f6, THREAD_FPR6(\thread)
70 ldc1 $f8, THREAD_FPR8(\thread)
71 ldc1 $f10, THREAD_FPR10(\thread)
72 ldc1 $f12, THREAD_FPR12(\thread)
73 ldc1 $f14, THREAD_FPR14(\thread)
74 ldc1 $f16, THREAD_FPR16(\thread)
75 ldc1 $f18, THREAD_FPR18(\thread)
76 ldc1 $f20, THREAD_FPR20(\thread)
77 ldc1 $f22, THREAD_FPR22(\thread)
78 ldc1 $f24, THREAD_FPR24(\thread)
79 ldc1 $f26, THREAD_FPR26(\thread)
80 ldc1 $f28, THREAD_FPR28(\thread)
81 ldc1 $f30, THREAD_FPR30(\thread)
82 ctc1 \tmp, fcr31
83 .endm
84
85 .macro fpu_restore_16odd thread
86 ldc1 $f1, THREAD_FPR1(\thread)
87 ldc1 $f3, THREAD_FPR3(\thread)
88 ldc1 $f5, THREAD_FPR5(\thread)
89 ldc1 $f7, THREAD_FPR7(\thread)
90 ldc1 $f9, THREAD_FPR9(\thread)
91 ldc1 $f11, THREAD_FPR11(\thread)
92 ldc1 $f13, THREAD_FPR13(\thread)
93 ldc1 $f15, THREAD_FPR15(\thread)
94 ldc1 $f17, THREAD_FPR17(\thread)
95 ldc1 $f19, THREAD_FPR19(\thread)
96 ldc1 $f21, THREAD_FPR21(\thread)
97 ldc1 $f23, THREAD_FPR23(\thread)
98 ldc1 $f25, THREAD_FPR25(\thread)
99 ldc1 $f27, THREAD_FPR27(\thread)
100 ldc1 $f29, THREAD_FPR29(\thread)
101 ldc1 $f31, THREAD_FPR31(\thread)
102 .endm
103
104 .macro fpu_restore_double thread status tmp
105 sll \tmp, \status, 5
106 bgez \tmp, 1f # 16 register mode?
107
108 fpu_restore_16odd \thread
1091: fpu_restore_16even \thread \tmp
110 .endm
111
112 .macro cpu_save_nonscratch thread 16 .macro cpu_save_nonscratch thread
113 LONG_S s0, THREAD_REG16(\thread) 17 LONG_S s0, THREAD_REG16(\thread)
114 LONG_S s1, THREAD_REG17(\thread) 18 LONG_S s1, THREAD_REG17(\thread)
diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h
index 6c8342ae74db..3220c93ea981 100644
--- a/arch/mips/include/asm/asmmacro.h
+++ b/arch/mips/include/asm/asmmacro.h
@@ -62,6 +62,113 @@
62 .endm 62 .endm
63#endif /* CONFIG_MIPS_MT_SMTC */ 63#endif /* CONFIG_MIPS_MT_SMTC */
64 64
65 .macro fpu_save_16even thread tmp=t0
66 cfc1 \tmp, fcr31
67 sdc1 $f0, THREAD_FPR0(\thread)
68 sdc1 $f2, THREAD_FPR2(\thread)
69 sdc1 $f4, THREAD_FPR4(\thread)
70 sdc1 $f6, THREAD_FPR6(\thread)
71 sdc1 $f8, THREAD_FPR8(\thread)
72 sdc1 $f10, THREAD_FPR10(\thread)
73 sdc1 $f12, THREAD_FPR12(\thread)
74 sdc1 $f14, THREAD_FPR14(\thread)
75 sdc1 $f16, THREAD_FPR16(\thread)
76 sdc1 $f18, THREAD_FPR18(\thread)
77 sdc1 $f20, THREAD_FPR20(\thread)
78 sdc1 $f22, THREAD_FPR22(\thread)
79 sdc1 $f24, THREAD_FPR24(\thread)
80 sdc1 $f26, THREAD_FPR26(\thread)
81 sdc1 $f28, THREAD_FPR28(\thread)
82 sdc1 $f30, THREAD_FPR30(\thread)
83 sw \tmp, THREAD_FCR31(\thread)
84 .endm
85
86 .macro fpu_save_16odd thread
87 .set push
88 .set mips64r2
89 sdc1 $f1, THREAD_FPR1(\thread)
90 sdc1 $f3, THREAD_FPR3(\thread)
91 sdc1 $f5, THREAD_FPR5(\thread)
92 sdc1 $f7, THREAD_FPR7(\thread)
93 sdc1 $f9, THREAD_FPR9(\thread)
94 sdc1 $f11, THREAD_FPR11(\thread)
95 sdc1 $f13, THREAD_FPR13(\thread)
96 sdc1 $f15, THREAD_FPR15(\thread)
97 sdc1 $f17, THREAD_FPR17(\thread)
98 sdc1 $f19, THREAD_FPR19(\thread)
99 sdc1 $f21, THREAD_FPR21(\thread)
100 sdc1 $f23, THREAD_FPR23(\thread)
101 sdc1 $f25, THREAD_FPR25(\thread)
102 sdc1 $f27, THREAD_FPR27(\thread)
103 sdc1 $f29, THREAD_FPR29(\thread)
104 sdc1 $f31, THREAD_FPR31(\thread)
105 .set pop
106 .endm
107
108 .macro fpu_save_double thread status tmp
109#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
110 sll \tmp, \status, 5
111 bgez \tmp, 10f
112 fpu_save_16odd \thread
11310:
114#endif
115 fpu_save_16even \thread \tmp
116 .endm
117
118 .macro fpu_restore_16even thread tmp=t0
119 lw \tmp, THREAD_FCR31(\thread)
120 ldc1 $f0, THREAD_FPR0(\thread)
121 ldc1 $f2, THREAD_FPR2(\thread)
122 ldc1 $f4, THREAD_FPR4(\thread)
123 ldc1 $f6, THREAD_FPR6(\thread)
124 ldc1 $f8, THREAD_FPR8(\thread)
125 ldc1 $f10, THREAD_FPR10(\thread)
126 ldc1 $f12, THREAD_FPR12(\thread)
127 ldc1 $f14, THREAD_FPR14(\thread)
128 ldc1 $f16, THREAD_FPR16(\thread)
129 ldc1 $f18, THREAD_FPR18(\thread)
130 ldc1 $f20, THREAD_FPR20(\thread)
131 ldc1 $f22, THREAD_FPR22(\thread)
132 ldc1 $f24, THREAD_FPR24(\thread)
133 ldc1 $f26, THREAD_FPR26(\thread)
134 ldc1 $f28, THREAD_FPR28(\thread)
135 ldc1 $f30, THREAD_FPR30(\thread)
136 ctc1 \tmp, fcr31
137 .endm
138
139 .macro fpu_restore_16odd thread
140 .set push
141 .set mips64r2
142 ldc1 $f1, THREAD_FPR1(\thread)
143 ldc1 $f3, THREAD_FPR3(\thread)
144 ldc1 $f5, THREAD_FPR5(\thread)
145 ldc1 $f7, THREAD_FPR7(\thread)
146 ldc1 $f9, THREAD_FPR9(\thread)
147 ldc1 $f11, THREAD_FPR11(\thread)
148 ldc1 $f13, THREAD_FPR13(\thread)
149 ldc1 $f15, THREAD_FPR15(\thread)
150 ldc1 $f17, THREAD_FPR17(\thread)
151 ldc1 $f19, THREAD_FPR19(\thread)
152 ldc1 $f21, THREAD_FPR21(\thread)
153 ldc1 $f23, THREAD_FPR23(\thread)
154 ldc1 $f25, THREAD_FPR25(\thread)
155 ldc1 $f27, THREAD_FPR27(\thread)
156 ldc1 $f29, THREAD_FPR29(\thread)
157 ldc1 $f31, THREAD_FPR31(\thread)
158 .set pop
159 .endm
160
161 .macro fpu_restore_double thread status tmp
162#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
163 sll \tmp, \status, 5
164 bgez \tmp, 10f # 16 register mode?
165
166 fpu_restore_16odd \thread
16710:
168#endif
169 fpu_restore_16even \thread \tmp
170 .endm
171
65/* 172/*
66 * Temporary until all gas have MT ASE support 173 * Temporary until all gas have MT ASE support
67 */ 174 */
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
index a66359ef4ece..d4144056e928 100644
--- a/arch/mips/include/asm/elf.h
+++ b/arch/mips/include/asm/elf.h
@@ -36,6 +36,7 @@
36#define EF_MIPS_ABI2 0x00000020 36#define EF_MIPS_ABI2 0x00000020
37#define EF_MIPS_OPTIONS_FIRST 0x00000080 37#define EF_MIPS_OPTIONS_FIRST 0x00000080
38#define EF_MIPS_32BITMODE 0x00000100 38#define EF_MIPS_32BITMODE 0x00000100
39#define EF_MIPS_FP64 0x00000200
39#define EF_MIPS_ABI 0x0000f000 40#define EF_MIPS_ABI 0x0000f000
40#define EF_MIPS_ARCH 0xf0000000 41#define EF_MIPS_ARCH 0xf0000000
41 42
@@ -176,6 +177,18 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
176#ifdef CONFIG_32BIT 177#ifdef CONFIG_32BIT
177 178
178/* 179/*
180 * In order to be sure that we don't attempt to execute an O32 binary which
181 * requires 64 bit FP (FR=1) on a system which does not support it we refuse
182 * to execute any binary which has bits specified by the following macro set
183 * in its ELF header flags.
184 */
185#ifdef CONFIG_MIPS_O32_FP64_SUPPORT
186# define __MIPS_O32_FP64_MUST_BE_ZERO 0
187#else
188# define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64
189#endif
190
191/*
179 * This is used to ensure we don't load something for the wrong architecture. 192 * This is used to ensure we don't load something for the wrong architecture.
180 */ 193 */
181#define elf_check_arch(hdr) \ 194#define elf_check_arch(hdr) \
@@ -192,6 +205,8 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
192 if (((__h->e_flags & EF_MIPS_ABI) != 0) && \ 205 if (((__h->e_flags & EF_MIPS_ABI) != 0) && \
193 ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \ 206 ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \
194 __res = 0; \ 207 __res = 0; \
208 if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \
209 __res = 0; \
195 \ 210 \
196 __res; \ 211 __res; \
197}) 212})
@@ -249,6 +264,11 @@ extern struct mips_abi mips_abi_n32;
249 264
250#define SET_PERSONALITY(ex) \ 265#define SET_PERSONALITY(ex) \
251do { \ 266do { \
267 if ((ex).e_flags & EF_MIPS_FP64) \
268 clear_thread_flag(TIF_32BIT_FPREGS); \
269 else \
270 set_thread_flag(TIF_32BIT_FPREGS); \
271 \
252 if (personality(current->personality) != PER_LINUX) \ 272 if (personality(current->personality) != PER_LINUX) \
253 set_personality(PER_LINUX); \ 273 set_personality(PER_LINUX); \
254 \ 274 \
@@ -271,14 +291,18 @@ do { \
271#endif 291#endif
272 292
273#ifdef CONFIG_MIPS32_O32 293#ifdef CONFIG_MIPS32_O32
274#define __SET_PERSONALITY32_O32() \ 294#define __SET_PERSONALITY32_O32(ex) \
275 do { \ 295 do { \
276 set_thread_flag(TIF_32BIT_REGS); \ 296 set_thread_flag(TIF_32BIT_REGS); \
277 set_thread_flag(TIF_32BIT_ADDR); \ 297 set_thread_flag(TIF_32BIT_ADDR); \
298 \
299 if (!((ex).e_flags & EF_MIPS_FP64)) \
300 set_thread_flag(TIF_32BIT_FPREGS); \
301 \
278 current->thread.abi = &mips_abi_32; \ 302 current->thread.abi = &mips_abi_32; \
279 } while (0) 303 } while (0)
280#else 304#else
281#define __SET_PERSONALITY32_O32() \ 305#define __SET_PERSONALITY32_O32(ex) \
282 do { } while (0) 306 do { } while (0)
283#endif 307#endif
284 308
@@ -289,7 +313,7 @@ do { \
289 ((ex).e_flags & EF_MIPS_ABI) == 0) \ 313 ((ex).e_flags & EF_MIPS_ABI) == 0) \
290 __SET_PERSONALITY32_N32(); \ 314 __SET_PERSONALITY32_N32(); \
291 else \ 315 else \
292 __SET_PERSONALITY32_O32(); \ 316 __SET_PERSONALITY32_O32(ex); \
293} while (0) 317} while (0)
294#else 318#else
295#define __SET_PERSONALITY32(ex) do { } while (0) 319#define __SET_PERSONALITY32(ex) do { } while (0)
@@ -300,6 +324,7 @@ do { \
300 unsigned int p; \ 324 unsigned int p; \
301 \ 325 \
302 clear_thread_flag(TIF_32BIT_REGS); \ 326 clear_thread_flag(TIF_32BIT_REGS); \
327 clear_thread_flag(TIF_32BIT_FPREGS); \
303 clear_thread_flag(TIF_32BIT_ADDR); \ 328 clear_thread_flag(TIF_32BIT_ADDR); \
304 \ 329 \
305 if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \ 330 if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \
diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h
index 3bf023fde482..cfe092fc720d 100644
--- a/arch/mips/include/asm/fpu.h
+++ b/arch/mips/include/asm/fpu.h
@@ -33,11 +33,48 @@ extern void _init_fpu(void);
33extern void _save_fp(struct task_struct *); 33extern void _save_fp(struct task_struct *);
34extern void _restore_fp(struct task_struct *); 34extern void _restore_fp(struct task_struct *);
35 35
36#define __enable_fpu() \ 36/*
37do { \ 37 * This enum specifies a mode in which we want the FPU to operate, for cores
38 set_c0_status(ST0_CU1); \ 38 * which implement the Status.FR bit. Note that FPU_32BIT & FPU_64BIT
39 enable_fpu_hazard(); \ 39 * purposefully have the values 0 & 1 respectively, so that an integer value
40} while (0) 40 * of Status.FR can be trivially casted to the corresponding enum fpu_mode.
41 */
42enum fpu_mode {
43 FPU_32BIT = 0, /* FR = 0 */
44 FPU_64BIT, /* FR = 1 */
45 FPU_AS_IS,
46};
47
48static inline int __enable_fpu(enum fpu_mode mode)
49{
50 int fr;
51
52 switch (mode) {
53 case FPU_AS_IS:
54 /* just enable the FPU in its current mode */
55 set_c0_status(ST0_CU1);
56 enable_fpu_hazard();
57 return 0;
58
59 case FPU_64BIT:
60#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_MIPS64))
61 /* we only have a 32-bit FPU */
62 return SIGFPE;
63#endif
64 /* fall through */
65 case FPU_32BIT:
66 /* set CU1 & change FR appropriately */
67 fr = (int)mode;
68 change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | (fr ? ST0_FR : 0));
69 enable_fpu_hazard();
70
71 /* check FR has the desired value */
72 return (!!(read_c0_status() & ST0_FR) == !!fr) ? 0 : SIGFPE;
73
74 default:
75 BUG();
76 }
77}
41 78
42#define __disable_fpu() \ 79#define __disable_fpu() \
43do { \ 80do { \
@@ -57,27 +94,46 @@ static inline int is_fpu_owner(void)
57 return cpu_has_fpu && __is_fpu_owner(); 94 return cpu_has_fpu && __is_fpu_owner();
58} 95}
59 96
60static inline void __own_fpu(void) 97static inline int __own_fpu(void)
61{ 98{
62 __enable_fpu(); 99 enum fpu_mode mode;
100 int ret;
101
102 mode = !test_thread_flag(TIF_32BIT_FPREGS);
103 ret = __enable_fpu(mode);
104 if (ret)
105 return ret;
106
63 KSTK_STATUS(current) |= ST0_CU1; 107 KSTK_STATUS(current) |= ST0_CU1;
108 if (mode == FPU_64BIT)
109 KSTK_STATUS(current) |= ST0_FR;
110 else /* mode == FPU_32BIT */
111 KSTK_STATUS(current) &= ~ST0_FR;
112
64 set_thread_flag(TIF_USEDFPU); 113 set_thread_flag(TIF_USEDFPU);
114 return 0;
65} 115}
66 116
67static inline void own_fpu_inatomic(int restore) 117static inline int own_fpu_inatomic(int restore)
68{ 118{
119 int ret = 0;
120
69 if (cpu_has_fpu && !__is_fpu_owner()) { 121 if (cpu_has_fpu && !__is_fpu_owner()) {
70 __own_fpu(); 122 ret = __own_fpu();
71 if (restore) 123 if (restore && !ret)
72 _restore_fp(current); 124 _restore_fp(current);
73 } 125 }
126 return ret;
74} 127}
75 128
76static inline void own_fpu(int restore) 129static inline int own_fpu(int restore)
77{ 130{
131 int ret;
132
78 preempt_disable(); 133 preempt_disable();
79 own_fpu_inatomic(restore); 134 ret = own_fpu_inatomic(restore);
80 preempt_enable(); 135 preempt_enable();
136 return ret;
81} 137}
82 138
83static inline void lose_fpu(int save) 139static inline void lose_fpu(int save)
@@ -93,16 +149,21 @@ static inline void lose_fpu(int save)
93 preempt_enable(); 149 preempt_enable();
94} 150}
95 151
96static inline void init_fpu(void) 152static inline int init_fpu(void)
97{ 153{
154 int ret = 0;
155
98 preempt_disable(); 156 preempt_disable();
99 if (cpu_has_fpu) { 157 if (cpu_has_fpu) {
100 __own_fpu(); 158 ret = __own_fpu();
101 _init_fpu(); 159 if (!ret)
160 _init_fpu();
102 } else { 161 } else {
103 fpu_emulator_init_fpu(); 162 fpu_emulator_init_fpu();
104 } 163 }
164
105 preempt_enable(); 165 preempt_enable();
166 return ret;
106} 167}
107 168
108static inline void save_fp(struct task_struct *tsk) 169static inline void save_fp(struct task_struct *tsk)
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index 4f58ef6d0eed..24846f9053fe 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -110,11 +110,12 @@ static inline struct thread_info *current_thread_info(void)
110#define TIF_NOHZ 19 /* in adaptive nohz mode */ 110#define TIF_NOHZ 19 /* in adaptive nohz mode */
111#define TIF_FIXADE 20 /* Fix address errors in software */ 111#define TIF_FIXADE 20 /* Fix address errors in software */
112#define TIF_LOGADE 21 /* Log address errors to syslog */ 112#define TIF_LOGADE 21 /* Log address errors to syslog */
113#define TIF_32BIT_REGS 22 /* also implies 16/32 fprs */ 113#define TIF_32BIT_REGS 22 /* 32-bit general purpose registers */
114#define TIF_32BIT_ADDR 23 /* 32-bit address space (o32/n32) */ 114#define TIF_32BIT_ADDR 23 /* 32-bit address space (o32/n32) */
115#define TIF_FPUBOUND 24 /* thread bound to FPU-full CPU set */ 115#define TIF_FPUBOUND 24 /* thread bound to FPU-full CPU set */
116#define TIF_LOAD_WATCH 25 /* If set, load watch registers */ 116#define TIF_LOAD_WATCH 25 /* If set, load watch registers */
117#define TIF_SYSCALL_TRACEPOINT 26 /* syscall tracepoint instrumentation */ 117#define TIF_SYSCALL_TRACEPOINT 26 /* syscall tracepoint instrumentation */
118#define TIF_32BIT_FPREGS 27 /* 32-bit floating point registers */
118#define TIF_SYSCALL_TRACE 31 /* syscall trace active */ 119#define TIF_SYSCALL_TRACE 31 /* syscall trace active */
119 120
120#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) 121#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -131,6 +132,7 @@ static inline struct thread_info *current_thread_info(void)
131#define _TIF_32BIT_ADDR (1<<TIF_32BIT_ADDR) 132#define _TIF_32BIT_ADDR (1<<TIF_32BIT_ADDR)
132#define _TIF_FPUBOUND (1<<TIF_FPUBOUND) 133#define _TIF_FPUBOUND (1<<TIF_FPUBOUND)
133#define _TIF_LOAD_WATCH (1<<TIF_LOAD_WATCH) 134#define _TIF_LOAD_WATCH (1<<TIF_LOAD_WATCH)
135#define _TIF_32BIT_FPREGS (1<<TIF_32BIT_FPREGS)
134#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT) 136#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
135 137
136#define _TIF_WORK_SYSCALL_ENTRY (_TIF_NOHZ | _TIF_SYSCALL_TRACE | \ 138#define _TIF_WORK_SYSCALL_ENTRY (_TIF_NOHZ | _TIF_SYSCALL_TRACE | \
diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c
index 202e581e6096..7faf5f2bee25 100644
--- a/arch/mips/kernel/binfmt_elfo32.c
+++ b/arch/mips/kernel/binfmt_elfo32.c
@@ -28,6 +28,18 @@ typedef double elf_fpreg_t;
28typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; 28typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
29 29
30/* 30/*
31 * In order to be sure that we don't attempt to execute an O32 binary which
32 * requires 64 bit FP (FR=1) on a system which does not support it we refuse
33 * to execute any binary which has bits specified by the following macro set
34 * in its ELF header flags.
35 */
36#ifdef CONFIG_MIPS_O32_FP64_SUPPORT
37# define __MIPS_O32_FP64_MUST_BE_ZERO 0
38#else
39# define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64
40#endif
41
42/*
31 * This is used to ensure we don't load something for the wrong architecture. 43 * This is used to ensure we don't load something for the wrong architecture.
32 */ 44 */
33#define elf_check_arch(hdr) \ 45#define elf_check_arch(hdr) \
@@ -44,6 +56,8 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
44 if (((__h->e_flags & EF_MIPS_ABI) != 0) && \ 56 if (((__h->e_flags & EF_MIPS_ABI) != 0) && \
45 ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \ 57 ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \
46 __res = 0; \ 58 __res = 0; \
59 if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \
60 __res = 0; \
47 \ 61 \
48 __res; \ 62 __res; \
49}) 63})
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index c814287bdf5d..e2b2d2043701 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -112,7 +112,7 @@ static inline unsigned long cpu_get_fpu_id(void)
112 unsigned long tmp, fpu_id; 112 unsigned long tmp, fpu_id;
113 113
114 tmp = read_c0_status(); 114 tmp = read_c0_status();
115 __enable_fpu(); 115 __enable_fpu(FPU_AS_IS);
116 fpu_id = read_32bit_cp1_register(CP1_REVISION); 116 fpu_id = read_32bit_cp1_register(CP1_REVISION);
117 write_c0_status(tmp); 117 write_c0_status(tmp);
118 return fpu_id; 118 return fpu_id;
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index ddc76103e78c..747a6cfbb709 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -60,9 +60,6 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
60 60
61 /* New thread loses kernel privileges. */ 61 /* New thread loses kernel privileges. */
62 status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK); 62 status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK);
63#ifdef CONFIG_64BIT
64 status |= test_thread_flag(TIF_32BIT_REGS) ? 0 : ST0_FR;
65#endif
66 status |= KU_USER; 63 status |= KU_USER;
67 regs->cp0_status = status; 64 regs->cp0_status = status;
68 clear_used_math(); 65 clear_used_math();
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index b52e1d2b33e0..7da9b76db4d9 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -137,13 +137,13 @@ int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
137 if (cpu_has_mipsmt) { 137 if (cpu_has_mipsmt) {
138 unsigned int vpflags = dvpe(); 138 unsigned int vpflags = dvpe();
139 flags = read_c0_status(); 139 flags = read_c0_status();
140 __enable_fpu(); 140 __enable_fpu(FPU_AS_IS);
141 __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); 141 __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
142 write_c0_status(flags); 142 write_c0_status(flags);
143 evpe(vpflags); 143 evpe(vpflags);
144 } else { 144 } else {
145 flags = read_c0_status(); 145 flags = read_c0_status();
146 __enable_fpu(); 146 __enable_fpu(FPU_AS_IS);
147 __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); 147 __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
148 write_c0_status(flags); 148 write_c0_status(flags);
149 } 149 }
@@ -408,6 +408,7 @@ long arch_ptrace(struct task_struct *child, long request,
408 /* Read the word at location addr in the USER area. */ 408 /* Read the word at location addr in the USER area. */
409 case PTRACE_PEEKUSR: { 409 case PTRACE_PEEKUSR: {
410 struct pt_regs *regs; 410 struct pt_regs *regs;
411 fpureg_t *fregs;
411 unsigned long tmp = 0; 412 unsigned long tmp = 0;
412 413
413 regs = task_pt_regs(child); 414 regs = task_pt_regs(child);
@@ -418,26 +419,28 @@ long arch_ptrace(struct task_struct *child, long request,
418 tmp = regs->regs[addr]; 419 tmp = regs->regs[addr];
419 break; 420 break;
420 case FPR_BASE ... FPR_BASE + 31: 421 case FPR_BASE ... FPR_BASE + 31:
421 if (tsk_used_math(child)) { 422 if (!tsk_used_math(child)) {
422 fpureg_t *fregs = get_fpu_regs(child); 423 /* FP not yet used */
424 tmp = -1;
425 break;
426 }
427 fregs = get_fpu_regs(child);
423 428
424#ifdef CONFIG_32BIT 429#ifdef CONFIG_32BIT
430 if (test_thread_flag(TIF_32BIT_FPREGS)) {
425 /* 431 /*
426 * The odd registers are actually the high 432 * The odd registers are actually the high
427 * order bits of the values stored in the even 433 * order bits of the values stored in the even
428 * registers - unless we're using r2k_switch.S. 434 * registers - unless we're using r2k_switch.S.
429 */ 435 */
430 if (addr & 1) 436 if (addr & 1)
431 tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32); 437 tmp = fregs[(addr & ~1) - 32] >> 32;
432 else 438 else
433 tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff); 439 tmp = fregs[addr - 32];
434#endif 440 break;
435#ifdef CONFIG_64BIT
436 tmp = fregs[addr - FPR_BASE];
437#endif
438 } else {
439 tmp = -1; /* FP not yet used */
440 } 441 }
442#endif
443 tmp = fregs[addr - FPR_BASE];
441 break; 444 break;
442 case PC: 445 case PC:
443 tmp = regs->cp0_epc; 446 tmp = regs->cp0_epc;
@@ -483,13 +486,13 @@ long arch_ptrace(struct task_struct *child, long request,
483 if (cpu_has_mipsmt) { 486 if (cpu_has_mipsmt) {
484 unsigned int vpflags = dvpe(); 487 unsigned int vpflags = dvpe();
485 flags = read_c0_status(); 488 flags = read_c0_status();
486 __enable_fpu(); 489 __enable_fpu(FPU_AS_IS);
487 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); 490 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
488 write_c0_status(flags); 491 write_c0_status(flags);
489 evpe(vpflags); 492 evpe(vpflags);
490 } else { 493 } else {
491 flags = read_c0_status(); 494 flags = read_c0_status();
492 __enable_fpu(); 495 __enable_fpu(FPU_AS_IS);
493 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); 496 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
494 write_c0_status(flags); 497 write_c0_status(flags);
495 } 498 }
@@ -554,22 +557,25 @@ long arch_ptrace(struct task_struct *child, long request,
554 child->thread.fpu.fcr31 = 0; 557 child->thread.fpu.fcr31 = 0;
555 } 558 }
556#ifdef CONFIG_32BIT 559#ifdef CONFIG_32BIT
557 /* 560 if (test_thread_flag(TIF_32BIT_FPREGS)) {
558 * The odd registers are actually the high order bits 561 /*
559 * of the values stored in the even registers - unless 562 * The odd registers are actually the high
560 * we're using r2k_switch.S. 563 * order bits of the values stored in the even
561 */ 564 * registers - unless we're using r2k_switch.S.
562 if (addr & 1) { 565 */
563 fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff; 566 if (addr & 1) {
564 fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32; 567 fregs[(addr & ~1) - FPR_BASE] &=
565 } else { 568 0xffffffff;
566 fregs[addr - FPR_BASE] &= ~0xffffffffLL; 569 fregs[(addr & ~1) - FPR_BASE] |=
567 fregs[addr - FPR_BASE] |= data; 570 ((u64)data) << 32;
571 } else {
572 fregs[addr - FPR_BASE] &= ~0xffffffffLL;
573 fregs[addr - FPR_BASE] |= data;
574 }
575 break;
568 } 576 }
569#endif 577#endif
570#ifdef CONFIG_64BIT
571 fregs[addr - FPR_BASE] = data; 578 fregs[addr - FPR_BASE] = data;
572#endif
573 break; 579 break;
574 } 580 }
575 case PC: 581 case PC:
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index 9486055ba660..b8aa2dd5b00b 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -80,6 +80,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
80 /* Read the word at location addr in the USER area. */ 80 /* Read the word at location addr in the USER area. */
81 case PTRACE_PEEKUSR: { 81 case PTRACE_PEEKUSR: {
82 struct pt_regs *regs; 82 struct pt_regs *regs;
83 fpureg_t *fregs;
83 unsigned int tmp; 84 unsigned int tmp;
84 85
85 regs = task_pt_regs(child); 86 regs = task_pt_regs(child);
@@ -90,21 +91,25 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
90 tmp = regs->regs[addr]; 91 tmp = regs->regs[addr];
91 break; 92 break;
92 case FPR_BASE ... FPR_BASE + 31: 93 case FPR_BASE ... FPR_BASE + 31:
93 if (tsk_used_math(child)) { 94 if (!tsk_used_math(child)) {
94 fpureg_t *fregs = get_fpu_regs(child); 95 /* FP not yet used */
95 96 tmp = -1;
97 break;
98 }
99 fregs = get_fpu_regs(child);
100 if (test_thread_flag(TIF_32BIT_FPREGS)) {
96 /* 101 /*
97 * The odd registers are actually the high 102 * The odd registers are actually the high
98 * order bits of the values stored in the even 103 * order bits of the values stored in the even
99 * registers - unless we're using r2k_switch.S. 104 * registers - unless we're using r2k_switch.S.
100 */ 105 */
101 if (addr & 1) 106 if (addr & 1)
102 tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32); 107 tmp = fregs[(addr & ~1) - 32] >> 32;
103 else 108 else
104 tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff); 109 tmp = fregs[addr - 32];
105 } else { 110 break;
106 tmp = -1; /* FP not yet used */
107 } 111 }
112 tmp = fregs[addr - FPR_BASE];
108 break; 113 break;
109 case PC: 114 case PC:
110 tmp = regs->cp0_epc; 115 tmp = regs->cp0_epc;
@@ -147,13 +152,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
147 if (cpu_has_mipsmt) { 152 if (cpu_has_mipsmt) {
148 unsigned int vpflags = dvpe(); 153 unsigned int vpflags = dvpe();
149 flags = read_c0_status(); 154 flags = read_c0_status();
150 __enable_fpu(); 155 __enable_fpu(FPU_AS_IS);
151 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); 156 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
152 write_c0_status(flags); 157 write_c0_status(flags);
153 evpe(vpflags); 158 evpe(vpflags);
154 } else { 159 } else {
155 flags = read_c0_status(); 160 flags = read_c0_status();
156 __enable_fpu(); 161 __enable_fpu(FPU_AS_IS);
157 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); 162 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
158 write_c0_status(flags); 163 write_c0_status(flags);
159 } 164 }
@@ -236,20 +241,24 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
236 sizeof(child->thread.fpu)); 241 sizeof(child->thread.fpu));
237 child->thread.fpu.fcr31 = 0; 242 child->thread.fpu.fcr31 = 0;
238 } 243 }
239 /* 244 if (test_thread_flag(TIF_32BIT_FPREGS)) {
240 * The odd registers are actually the high order bits 245 /*
241 * of the values stored in the even registers - unless 246 * The odd registers are actually the high
242 * we're using r2k_switch.S. 247 * order bits of the values stored in the even
243 */ 248 * registers - unless we're using r2k_switch.S.
244 if (addr & 1) { 249 */
245 fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff; 250 if (addr & 1) {
246 fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32; 251 fregs[(addr & ~1) - FPR_BASE] &=
247 } else { 252 0xffffffff;
248 fregs[addr - FPR_BASE] &= ~0xffffffffLL; 253 fregs[(addr & ~1) - FPR_BASE] |=
249 /* Must cast, lest sign extension fill upper 254 ((u64)data) << 32;
250 bits! */ 255 } else {
251 fregs[addr - FPR_BASE] |= (unsigned int)data; 256 fregs[addr - FPR_BASE] &= ~0xffffffffLL;
257 fregs[addr - FPR_BASE] |= data;
258 }
259 break;
252 } 260 }
261 fregs[addr - FPR_BASE] = data;
253 break; 262 break;
254 } 263 }
255 case PC: 264 case PC:
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S
index 55ffe149dae9..253b2fb52026 100644
--- a/arch/mips/kernel/r4k_fpu.S
+++ b/arch/mips/kernel/r4k_fpu.S
@@ -35,7 +35,15 @@
35LEAF(_save_fp_context) 35LEAF(_save_fp_context)
36 cfc1 t1, fcr31 36 cfc1 t1, fcr31
37 37
38#ifdef CONFIG_64BIT 38#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
39 .set push
40#ifdef CONFIG_MIPS32_R2
41 .set mips64r2
42 mfc0 t0, CP0_STATUS
43 sll t0, t0, 5
44 bgez t0, 1f # skip storing odd if FR=0
45 nop
46#endif
39 /* Store the 16 odd double precision registers */ 47 /* Store the 16 odd double precision registers */
40 EX sdc1 $f1, SC_FPREGS+8(a0) 48 EX sdc1 $f1, SC_FPREGS+8(a0)
41 EX sdc1 $f3, SC_FPREGS+24(a0) 49 EX sdc1 $f3, SC_FPREGS+24(a0)
@@ -53,6 +61,7 @@ LEAF(_save_fp_context)
53 EX sdc1 $f27, SC_FPREGS+216(a0) 61 EX sdc1 $f27, SC_FPREGS+216(a0)
54 EX sdc1 $f29, SC_FPREGS+232(a0) 62 EX sdc1 $f29, SC_FPREGS+232(a0)
55 EX sdc1 $f31, SC_FPREGS+248(a0) 63 EX sdc1 $f31, SC_FPREGS+248(a0)
641: .set pop
56#endif 65#endif
57 66
58 /* Store the 16 even double precision registers */ 67 /* Store the 16 even double precision registers */
@@ -82,7 +91,31 @@ LEAF(_save_fp_context)
82LEAF(_save_fp_context32) 91LEAF(_save_fp_context32)
83 cfc1 t1, fcr31 92 cfc1 t1, fcr31
84 93
85 EX sdc1 $f0, SC32_FPREGS+0(a0) 94 mfc0 t0, CP0_STATUS
95 sll t0, t0, 5
96 bgez t0, 1f # skip storing odd if FR=0
97 nop
98
99 /* Store the 16 odd double precision registers */
100 EX sdc1 $f1, SC32_FPREGS+8(a0)
101 EX sdc1 $f3, SC32_FPREGS+24(a0)
102 EX sdc1 $f5, SC32_FPREGS+40(a0)
103 EX sdc1 $f7, SC32_FPREGS+56(a0)
104 EX sdc1 $f9, SC32_FPREGS+72(a0)
105 EX sdc1 $f11, SC32_FPREGS+88(a0)
106 EX sdc1 $f13, SC32_FPREGS+104(a0)
107 EX sdc1 $f15, SC32_FPREGS+120(a0)
108 EX sdc1 $f17, SC32_FPREGS+136(a0)
109 EX sdc1 $f19, SC32_FPREGS+152(a0)
110 EX sdc1 $f21, SC32_FPREGS+168(a0)
111 EX sdc1 $f23, SC32_FPREGS+184(a0)
112 EX sdc1 $f25, SC32_FPREGS+200(a0)
113 EX sdc1 $f27, SC32_FPREGS+216(a0)
114 EX sdc1 $f29, SC32_FPREGS+232(a0)
115 EX sdc1 $f31, SC32_FPREGS+248(a0)
116
117 /* Store the 16 even double precision registers */
1181: EX sdc1 $f0, SC32_FPREGS+0(a0)
86 EX sdc1 $f2, SC32_FPREGS+16(a0) 119 EX sdc1 $f2, SC32_FPREGS+16(a0)
87 EX sdc1 $f4, SC32_FPREGS+32(a0) 120 EX sdc1 $f4, SC32_FPREGS+32(a0)
88 EX sdc1 $f6, SC32_FPREGS+48(a0) 121 EX sdc1 $f6, SC32_FPREGS+48(a0)
@@ -114,7 +147,16 @@ LEAF(_save_fp_context32)
114 */ 147 */
115LEAF(_restore_fp_context) 148LEAF(_restore_fp_context)
116 EX lw t0, SC_FPC_CSR(a0) 149 EX lw t0, SC_FPC_CSR(a0)
117#ifdef CONFIG_64BIT 150
151#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
152 .set push
153#ifdef CONFIG_MIPS32_R2
154 .set mips64r2
155 mfc0 t0, CP0_STATUS
156 sll t0, t0, 5
157 bgez t0, 1f # skip loading odd if FR=0
158 nop
159#endif
118 EX ldc1 $f1, SC_FPREGS+8(a0) 160 EX ldc1 $f1, SC_FPREGS+8(a0)
119 EX ldc1 $f3, SC_FPREGS+24(a0) 161 EX ldc1 $f3, SC_FPREGS+24(a0)
120 EX ldc1 $f5, SC_FPREGS+40(a0) 162 EX ldc1 $f5, SC_FPREGS+40(a0)
@@ -131,6 +173,7 @@ LEAF(_restore_fp_context)
131 EX ldc1 $f27, SC_FPREGS+216(a0) 173 EX ldc1 $f27, SC_FPREGS+216(a0)
132 EX ldc1 $f29, SC_FPREGS+232(a0) 174 EX ldc1 $f29, SC_FPREGS+232(a0)
133 EX ldc1 $f31, SC_FPREGS+248(a0) 175 EX ldc1 $f31, SC_FPREGS+248(a0)
1761: .set pop
134#endif 177#endif
135 EX ldc1 $f0, SC_FPREGS+0(a0) 178 EX ldc1 $f0, SC_FPREGS+0(a0)
136 EX ldc1 $f2, SC_FPREGS+16(a0) 179 EX ldc1 $f2, SC_FPREGS+16(a0)
@@ -157,7 +200,30 @@ LEAF(_restore_fp_context)
157LEAF(_restore_fp_context32) 200LEAF(_restore_fp_context32)
158 /* Restore an o32 sigcontext. */ 201 /* Restore an o32 sigcontext. */
159 EX lw t0, SC32_FPC_CSR(a0) 202 EX lw t0, SC32_FPC_CSR(a0)
160 EX ldc1 $f0, SC32_FPREGS+0(a0) 203
204 mfc0 t0, CP0_STATUS
205 sll t0, t0, 5
206 bgez t0, 1f # skip loading odd if FR=0
207 nop
208
209 EX ldc1 $f1, SC32_FPREGS+8(a0)
210 EX ldc1 $f3, SC32_FPREGS+24(a0)
211 EX ldc1 $f5, SC32_FPREGS+40(a0)
212 EX ldc1 $f7, SC32_FPREGS+56(a0)
213 EX ldc1 $f9, SC32_FPREGS+72(a0)
214 EX ldc1 $f11, SC32_FPREGS+88(a0)
215 EX ldc1 $f13, SC32_FPREGS+104(a0)
216 EX ldc1 $f15, SC32_FPREGS+120(a0)
217 EX ldc1 $f17, SC32_FPREGS+136(a0)
218 EX ldc1 $f19, SC32_FPREGS+152(a0)
219 EX ldc1 $f21, SC32_FPREGS+168(a0)
220 EX ldc1 $f23, SC32_FPREGS+184(a0)
221 EX ldc1 $f25, SC32_FPREGS+200(a0)
222 EX ldc1 $f27, SC32_FPREGS+216(a0)
223 EX ldc1 $f29, SC32_FPREGS+232(a0)
224 EX ldc1 $f31, SC32_FPREGS+248(a0)
225
2261: EX ldc1 $f0, SC32_FPREGS+0(a0)
161 EX ldc1 $f2, SC32_FPREGS+16(a0) 227 EX ldc1 $f2, SC32_FPREGS+16(a0)
162 EX ldc1 $f4, SC32_FPREGS+32(a0) 228 EX ldc1 $f4, SC32_FPREGS+32(a0)
163 EX ldc1 $f6, SC32_FPREGS+48(a0) 229 EX ldc1 $f6, SC32_FPREGS+48(a0)
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 078de5eaca8f..cc78dd9a17c7 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -123,7 +123,7 @@
123 * Save a thread's fp context. 123 * Save a thread's fp context.
124 */ 124 */
125LEAF(_save_fp) 125LEAF(_save_fp)
126#ifdef CONFIG_64BIT 126#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
127 mfc0 t0, CP0_STATUS 127 mfc0 t0, CP0_STATUS
128#endif 128#endif
129 fpu_save_double a0 t0 t1 # clobbers t1 129 fpu_save_double a0 t0 t1 # clobbers t1
@@ -134,7 +134,7 @@ LEAF(_save_fp)
134 * Restore a thread's fp context. 134 * Restore a thread's fp context.
135 */ 135 */
136LEAF(_restore_fp) 136LEAF(_restore_fp)
137#ifdef CONFIG_64BIT 137#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
138 mfc0 t0, CP0_STATUS 138 mfc0 t0, CP0_STATUS
139#endif 139#endif
140 fpu_restore_double a0 t0 t1 # clobbers t1 140 fpu_restore_double a0 t0 t1 # clobbers t1
@@ -228,6 +228,47 @@ LEAF(_init_fpu)
228 mtc1 t1, $f29 228 mtc1 t1, $f29
229 mtc1 t1, $f30 229 mtc1 t1, $f30
230 mtc1 t1, $f31 230 mtc1 t1, $f31
231
232#ifdef CONFIG_CPU_MIPS32_R2
233 .set push
234 .set mips64r2
235 sll t0, t0, 5 # is Status.FR set?
236 bgez t0, 1f # no: skip setting upper 32b
237
238 mthc1 t1, $f0
239 mthc1 t1, $f1
240 mthc1 t1, $f2
241 mthc1 t1, $f3
242 mthc1 t1, $f4
243 mthc1 t1, $f5
244 mthc1 t1, $f6
245 mthc1 t1, $f7
246 mthc1 t1, $f8
247 mthc1 t1, $f9
248 mthc1 t1, $f10
249 mthc1 t1, $f11
250 mthc1 t1, $f12
251 mthc1 t1, $f13
252 mthc1 t1, $f14
253 mthc1 t1, $f15
254 mthc1 t1, $f16
255 mthc1 t1, $f17
256 mthc1 t1, $f18
257 mthc1 t1, $f19
258 mthc1 t1, $f20
259 mthc1 t1, $f21
260 mthc1 t1, $f22
261 mthc1 t1, $f23
262 mthc1 t1, $f24
263 mthc1 t1, $f25
264 mthc1 t1, $f26
265 mthc1 t1, $f27
266 mthc1 t1, $f28
267 mthc1 t1, $f29
268 mthc1 t1, $f30
269 mthc1 t1, $f31
2701: .set pop
271#endif /* CONFIG_CPU_MIPS32_R2 */
231#else 272#else
232 .set mips3 273 .set mips3
233 dmtc1 t1, $f0 274 dmtc1 t1, $f0
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 2f285abc76d5..5199563c4403 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -71,8 +71,9 @@ static int protected_save_fp_context(struct sigcontext __user *sc)
71 int err; 71 int err;
72 while (1) { 72 while (1) {
73 lock_fpu_owner(); 73 lock_fpu_owner();
74 own_fpu_inatomic(1); 74 err = own_fpu_inatomic(1);
75 err = save_fp_context(sc); /* this might fail */ 75 if (!err)
76 err = save_fp_context(sc); /* this might fail */
76 unlock_fpu_owner(); 77 unlock_fpu_owner();
77 if (likely(!err)) 78 if (likely(!err))
78 break; 79 break;
@@ -91,8 +92,9 @@ static int protected_restore_fp_context(struct sigcontext __user *sc)
91 int err, tmp __maybe_unused; 92 int err, tmp __maybe_unused;
92 while (1) { 93 while (1) {
93 lock_fpu_owner(); 94 lock_fpu_owner();
94 own_fpu_inatomic(0); 95 err = own_fpu_inatomic(0);
95 err = restore_fp_context(sc); /* this might fail */ 96 if (!err)
97 err = restore_fp_context(sc); /* this might fail */
96 unlock_fpu_owner(); 98 unlock_fpu_owner();
97 if (likely(!err)) 99 if (likely(!err))
98 break; 100 break;
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 1905a419aa46..3d60f7750fa8 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -85,8 +85,9 @@ static int protected_save_fp_context32(struct sigcontext32 __user *sc)
85 int err; 85 int err;
86 while (1) { 86 while (1) {
87 lock_fpu_owner(); 87 lock_fpu_owner();
88 own_fpu_inatomic(1); 88 err = own_fpu_inatomic(1);
89 err = save_fp_context32(sc); /* this might fail */ 89 if (!err)
90 err = save_fp_context32(sc); /* this might fail */
90 unlock_fpu_owner(); 91 unlock_fpu_owner();
91 if (likely(!err)) 92 if (likely(!err))
92 break; 93 break;
@@ -105,8 +106,9 @@ static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
105 int err, tmp __maybe_unused; 106 int err, tmp __maybe_unused;
106 while (1) { 107 while (1) {
107 lock_fpu_owner(); 108 lock_fpu_owner();
108 own_fpu_inatomic(0); 109 err = own_fpu_inatomic(0);
109 err = restore_fp_context32(sc); /* this might fail */ 110 if (!err)
111 err = restore_fp_context32(sc); /* this might fail */
110 unlock_fpu_owner(); 112 unlock_fpu_owner();
111 if (likely(!err)) 113 if (likely(!err))
112 break; 114 break;
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index f9c8746be8d6..f40f688276c2 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1080,7 +1080,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
1080 unsigned long old_epc, old31; 1080 unsigned long old_epc, old31;
1081 unsigned int opcode; 1081 unsigned int opcode;
1082 unsigned int cpid; 1082 unsigned int cpid;
1083 int status; 1083 int status, err;
1084 unsigned long __maybe_unused flags; 1084 unsigned long __maybe_unused flags;
1085 1085
1086 prev_state = exception_enter(); 1086 prev_state = exception_enter();
@@ -1153,19 +1153,19 @@ asmlinkage void do_cpu(struct pt_regs *regs)
1153 1153
1154 case 1: 1154 case 1:
1155 if (used_math()) /* Using the FPU again. */ 1155 if (used_math()) /* Using the FPU again. */
1156 own_fpu(1); 1156 err = own_fpu(1);
1157 else { /* First time FPU user. */ 1157 else { /* First time FPU user. */
1158 init_fpu(); 1158 err = init_fpu();
1159 set_used_math(); 1159 set_used_math();
1160 } 1160 }
1161 1161
1162 if (!raw_cpu_has_fpu) { 1162 if (!raw_cpu_has_fpu || err) {
1163 int sig; 1163 int sig;
1164 void __user *fault_addr = NULL; 1164 void __user *fault_addr = NULL;
1165 sig = fpu_emulator_cop1Handler(regs, 1165 sig = fpu_emulator_cop1Handler(regs,
1166 &current->thread.fpu, 1166 &current->thread.fpu,
1167 0, &fault_addr); 1167 0, &fault_addr);
1168 if (!process_fpemu_return(sig, fault_addr)) 1168 if (!process_fpemu_return(sig, fault_addr) && !err)
1169 mt_ase_fp_affinity(); 1169 mt_ase_fp_affinity();
1170 } 1170 }
1171 1171
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index 0e47ae2aa96b..506925b2c3f3 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -859,20 +859,20 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
859 * In the Linux kernel, we support selection of FPR format on the 859 * In the Linux kernel, we support selection of FPR format on the
860 * basis of the Status.FR bit. If an FPU is not present, the FR bit 860 * basis of the Status.FR bit. If an FPU is not present, the FR bit
861 * is hardwired to zero, which would imply a 32-bit FPU even for 861 * is hardwired to zero, which would imply a 32-bit FPU even for
862 * 64-bit CPUs so we rather look at TIF_32BIT_REGS. 862 * 64-bit CPUs so we rather look at TIF_32BIT_FPREGS.
863 * FPU emu is slow and bulky and optimizing this function offers fairly 863 * FPU emu is slow and bulky and optimizing this function offers fairly
864 * sizeable benefits so we try to be clever and make this function return 864 * sizeable benefits so we try to be clever and make this function return
865 * a constant whenever possible, that is on 64-bit kernels without O32 865 * a constant whenever possible, that is on 64-bit kernels without O32
866 * compatibility enabled and on 32-bit kernels. 866 * compatibility enabled and on 32-bit without 64-bit FPU support.
867 */ 867 */
868static inline int cop1_64bit(struct pt_regs *xcp) 868static inline int cop1_64bit(struct pt_regs *xcp)
869{ 869{
870#if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32) 870#if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32)
871 return 1; 871 return 1;
872#elif defined(CONFIG_64BIT) && defined(CONFIG_MIPS32_O32) 872#elif defined(CONFIG_32BIT) && !defined(CONFIG_MIPS_O32_FP64_SUPPORT)
873 return !test_thread_flag(TIF_32BIT_REGS);
874#else
875 return 0; 873 return 0;
874#else
875 return !test_thread_flag(TIF_32BIT_FPREGS);
876#endif 876#endif
877} 877}
878 878
diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c
index 1c586575fe17..3aeae07ed5b8 100644
--- a/arch/mips/math-emu/kernel_linkage.c
+++ b/arch/mips/math-emu/kernel_linkage.c
@@ -89,8 +89,9 @@ int fpu_emulator_save_context32(struct sigcontext32 __user *sc)
89{ 89{
90 int i; 90 int i;
91 int err = 0; 91 int err = 0;
92 int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
92 93
93 for (i = 0; i < 32; i+=2) { 94 for (i = 0; i < 32; i += inc) {
94 err |= 95 err |=
95 __put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]); 96 __put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
96 } 97 }
@@ -103,8 +104,9 @@ int fpu_emulator_restore_context32(struct sigcontext32 __user *sc)
103{ 104{
104 int i; 105 int i;
105 int err = 0; 106 int err = 0;
107 int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
106 108
107 for (i = 0; i < 32; i+=2) { 109 for (i = 0; i < 32; i += inc) {
108 err |= 110 err |=
109 __get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]); 111 __get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
110 } 112 }