diff options
author | Paul Burton <paul.burton@imgtec.com> | 2013-11-22 08:12:07 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-01-13 17:40:56 -0500 |
commit | 597ce1723e0fa0bdbe2ae4c94f18da6e29b92635 (patch) | |
tree | 21f67268915b8457dd305c6bcf7ac905772fd0ee /arch | |
parent | 56a22d21bf9744315f56b2bbd6416170f27b7765 (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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/Kconfig | 17 | ||||
-rw-r--r-- | arch/mips/include/asm/asmmacro-32.h | 42 | ||||
-rw-r--r-- | arch/mips/include/asm/asmmacro-64.h | 96 | ||||
-rw-r--r-- | arch/mips/include/asm/asmmacro.h | 107 | ||||
-rw-r--r-- | arch/mips/include/asm/elf.h | 31 | ||||
-rw-r--r-- | arch/mips/include/asm/fpu.h | 91 | ||||
-rw-r--r-- | arch/mips/include/asm/thread_info.h | 4 | ||||
-rw-r--r-- | arch/mips/kernel/binfmt_elfo32.c | 14 | ||||
-rw-r--r-- | arch/mips/kernel/cpu-probe.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/process.c | 3 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace.c | 60 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace32.c | 53 | ||||
-rw-r--r-- | arch/mips/kernel/r4k_fpu.S | 74 | ||||
-rw-r--r-- | arch/mips/kernel/r4k_switch.S | 45 | ||||
-rw-r--r-- | arch/mips/kernel/signal.c | 10 | ||||
-rw-r--r-- | arch/mips/kernel/signal32.c | 10 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 10 | ||||
-rw-r--r-- | arch/mips/math-emu/cp1emu.c | 10 | ||||
-rw-r--r-- | arch/mips/math-emu/kernel_linkage.c | 6 |
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 | ||
2338 | config 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 | |||
2338 | config USE_OF | 2355 | config 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 | ||
60 | 2: | ||
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 | ||
109 | 1: 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 | ||
113 | 10: | ||
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 | ||
167 | 10: | ||
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) \ |
251 | do { \ | 266 | do { \ |
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); | |||
33 | extern void _save_fp(struct task_struct *); | 33 | extern void _save_fp(struct task_struct *); |
34 | extern void _restore_fp(struct task_struct *); | 34 | extern void _restore_fp(struct task_struct *); |
35 | 35 | ||
36 | #define __enable_fpu() \ | 36 | /* |
37 | do { \ | 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 | */ | ||
42 | enum fpu_mode { | ||
43 | FPU_32BIT = 0, /* FR = 0 */ | ||
44 | FPU_64BIT, /* FR = 1 */ | ||
45 | FPU_AS_IS, | ||
46 | }; | ||
47 | |||
48 | static 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() \ |
43 | do { \ | 80 | do { \ |
@@ -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 | ||
60 | static inline void __own_fpu(void) | 97 | static 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 | ||
67 | static inline void own_fpu_inatomic(int restore) | 117 | static 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 | ||
76 | static inline void own_fpu(int restore) | 129 | static 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 | ||
83 | static inline void lose_fpu(int save) | 139 | static 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 | ||
96 | static inline void init_fpu(void) | 152 | static 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 | ||
108 | static inline void save_fp(struct task_struct *tsk) | 169 | static 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; | |||
28 | typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; | 28 | typedef 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 @@ | |||
35 | LEAF(_save_fp_context) | 35 | LEAF(_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) |
64 | 1: .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) | |||
82 | LEAF(_save_fp_context32) | 91 | LEAF(_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 */ | ||
118 | 1: 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 | */ |
115 | LEAF(_restore_fp_context) | 148 | LEAF(_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) |
176 | 1: .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) | |||
157 | LEAF(_restore_fp_context32) | 200 | LEAF(_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 | |||
226 | 1: 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 | */ |
125 | LEAF(_save_fp) | 125 | LEAF(_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 | */ |
136 | LEAF(_restore_fp) | 136 | LEAF(_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 | ||
270 | 1: .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 | ¤t->thread.fpu, | 1166 | ¤t->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 | */ |
868 | static inline int cop1_64bit(struct pt_regs *xcp) | 868 | static 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 | } |