Skip to content

Commit 597ce17

Browse files
paulburtonralfbaechle
authored andcommitted
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 <[email protected]> Cc: [email protected] Cc: Paul Burton <[email protected]> Patchwork: https://patchwork.linux-mips.org/patch/6154/ Signed-off-by: Ralf Baechle <[email protected]>
1 parent 56a22d2 commit 597ce17

File tree

19 files changed

+449
-236
lines changed

19 files changed

+449
-236
lines changed

arch/mips/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2335,6 +2335,23 @@ config CC_STACKPROTECTOR
23352335

23362336
This feature requires gcc version 4.2 or above.
23372337

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+
23382355
config USE_OF
23392356
bool
23402357
select OF

arch/mips/include/asm/asmmacro-32.h

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,6 @@
1212
#include <asm/fpregdef.h>
1313
#include <asm/mipsregs.h>
1414

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-
3615
.macro fpu_save_single thread tmp=t0
3716
cfc1 \tmp, fcr31
3817
swc1 $f0, THREAD_FPR0(\thread)
@@ -70,27 +49,6 @@
7049
sw \tmp, THREAD_FCR31(\thread)
7150
.endm
7251

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-
9452
.macro fpu_restore_single thread tmp=t0
9553
lw \tmp, THREAD_FCR31(\thread)
9654
lwc1 $f0, THREAD_FPR0(\thread)

arch/mips/include/asm/asmmacro-64.h

Lines changed: 0 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -13,102 +13,6 @@
1313
#include <asm/fpregdef.h>
1414
#include <asm/mipsregs.h>
1515

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-
11216
.macro cpu_save_nonscratch thread
11317
LONG_S s0, THREAD_REG16(\thread)
11418
LONG_S s1, THREAD_REG17(\thread)

arch/mips/include/asm/asmmacro.h

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,113 @@
6262
.endm
6363
#endif /* CONFIG_MIPS_MT_SMTC */
6464

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+
65172
/*
66173
* Temporary until all gas have MT ASE support
67174
*/

arch/mips/include/asm/elf.h

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#define EF_MIPS_ABI2 0x00000020
3737
#define EF_MIPS_OPTIONS_FIRST 0x00000080
3838
#define EF_MIPS_32BITMODE 0x00000100
39+
#define EF_MIPS_FP64 0x00000200
3940
#define EF_MIPS_ABI 0x0000f000
4041
#define EF_MIPS_ARCH 0xf0000000
4142

@@ -175,6 +176,18 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
175176

176177
#ifdef CONFIG_32BIT
177178

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+
178191
/*
179192
* This is used to ensure we don't load something for the wrong architecture.
180193
*/
@@ -191,6 +204,8 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
191204
__res = 0; \
192205
if (((__h->e_flags & EF_MIPS_ABI) != 0) && \
193206
((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \
207+
__res = 0; \
208+
if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \
194209
__res = 0; \
195210
\
196211
__res; \
@@ -249,6 +264,11 @@ extern struct mips_abi mips_abi_n32;
249264

250265
#define SET_PERSONALITY(ex) \
251266
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+
\
252272
if (personality(current->personality) != PER_LINUX) \
253273
set_personality(PER_LINUX); \
254274
\
@@ -271,14 +291,18 @@ do { \
271291
#endif
272292

273293
#ifdef CONFIG_MIPS32_O32
274-
#define __SET_PERSONALITY32_O32() \
294+
#define __SET_PERSONALITY32_O32(ex) \
275295
do { \
276296
set_thread_flag(TIF_32BIT_REGS); \
277297
set_thread_flag(TIF_32BIT_ADDR); \
298+
\
299+
if (!((ex).e_flags & EF_MIPS_FP64)) \
300+
set_thread_flag(TIF_32BIT_FPREGS); \
301+
\
278302
current->thread.abi = &mips_abi_32; \
279303
} while (0)
280304
#else
281-
#define __SET_PERSONALITY32_O32() \
305+
#define __SET_PERSONALITY32_O32(ex) \
282306
do { } while (0)
283307
#endif
284308

@@ -289,7 +313,7 @@ do { \
289313
((ex).e_flags & EF_MIPS_ABI) == 0) \
290314
__SET_PERSONALITY32_N32(); \
291315
else \
292-
__SET_PERSONALITY32_O32(); \
316+
__SET_PERSONALITY32_O32(ex); \
293317
} while (0)
294318
#else
295319
#define __SET_PERSONALITY32(ex) do { } while (0)
@@ -300,6 +324,7 @@ do { \
300324
unsigned int p; \
301325
\
302326
clear_thread_flag(TIF_32BIT_REGS); \
327+
clear_thread_flag(TIF_32BIT_FPREGS); \
303328
clear_thread_flag(TIF_32BIT_ADDR); \
304329
\
305330
if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \

0 commit comments

Comments
 (0)