aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/r4k_fpu.S
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 /arch/mips/kernel/r4k_fpu.S
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>
Diffstat (limited to 'arch/mips/kernel/r4k_fpu.S')
-rw-r--r--arch/mips/kernel/r4k_fpu.S74
1 files changed, 70 insertions, 4 deletions
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)