1 /* Program execution for Emacs.
2
3 Copyright (C) 2023 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20 #include <config.h>
21 #include <errno.h>
22
23 #include "mipsfpu.h"
24
25
26
27 /* OABI MIPS systems support several different modes of execution.
28 Each mode differs in the size and utilization of the hardware
29 floating-point registers.
30
31 Linux normally sets the floating point mode to one appropriate for
32 execution, taking into account the floating point modes of the
33 interpreter and executable binaries. However, this logic is
34 forsaken when the `execve' system call is overwritten.
35
36 Thus, the correct floating point mode must be determined and set
37 within the loader binary. */
38
39
40
41 /* Various constants used throughout this code. */
42
43 #define MIPS_ABI_FP_ANY 0 /* FP ABI doesn't matter */
44 #define MIPS_ABI_FP_DOUBLE 1 /* -mdouble-float */
45 #define MIPS_ABI_FP_SINGLE 2 /* -msingle-float */
46 #define MIPS_ABI_FP_SOFT 3 /* -msoft-float */
47 #define MIPS_ABI_FP_OLD_64 4 /* -mips32r2 -mfp64 */
48 #define MIPS_ABI_FP_XX 5 /* -mfpxx */
49 #define MIPS_ABI_FP_64 6 /* -mips32r2 -mfp64 */
50 #define MIPS_ABI_FP_64A 7 /* -mips32r2 -mfp64 -mno-odd-spreg */
51
52 #define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used. */
53 #define EF_MIPS_PIC 2 /* Contains PIC code. */
54 #define EF_MIPS_CPIC 4 /* Uses PIC calling sequence. */
55 #define EF_MIPS_XGOT 8
56 #define EF_MIPS_64BIT_WHIRL 16
57 #define EF_MIPS_ABI2 32
58 #define EF_MIPS_ABI_ON32 64
59 #define EF_MIPS_FP64 512 /* Uses FP64 (12 callee-saved). */
60 #define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */
61 #define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */
62
63
64
65 /* Structure describing the requirements of a single floating-point
66 ABI. */
67
68 struct mode_description
69 {
70 /* Whether or not the ABI only executes single precision
71 instructions, and can operate in both 32-bit or 64-bit floating
72 point mode. */
73 bool single;
74
75 /* Whether or not the ABI performs floating point operations in
76 software, using integer registers. */
77 bool soft;
78
79 /* Whether or not the ABI requires the use of 64-bit floating point
80 registers. */
81 bool fr1;
82
83 /* Whether or not the ABI requires the use of 64-bit floating point
84 registers on NABI systems, and 32-bit ones on OABI systems. */
85 bool frdefault;
86
87 /* Whether or not this ABI requires single precision floating point
88 emulation. */
89 bool fre;
90 };
91
92 static struct mode_description fpu_reqs[] =
93 {
94 [MIPS_ABI_FP_ANY] = { true, true, true, true, true, },
95 [MIPS_ABI_FP_DOUBLE] = { false, false, false, true, true, },
96 [MIPS_ABI_FP_SINGLE] = { true, false, false, false, false, },
97 [MIPS_ABI_FP_SOFT] = { false, true, false, false, false, },
98 [MIPS_ABI_FP_OLD_64] = { false, false, false, false, false, },
99 [MIPS_ABI_FP_XX] = { false, false, true, true, true, },
100 [MIPS_ABI_FP_64] = { false, false, true, false, false, },
101 [MIPS_ABI_FP_64A] = { false, false, true, false, true, },
102 };
103
104
105
106 /* Return whether or not the given floating-point ABI is valid. */
107
108 static bool
109 valid_abi_p (int abi)
110 {
111 switch (abi)
112 {
113 case MIPS_ABI_FP_ANY:
114 case MIPS_ABI_FP_DOUBLE:
115 case MIPS_ABI_FP_SINGLE:
116 case MIPS_ABI_FP_SOFT:
117 case MIPS_ABI_FP_OLD_64:
118 case MIPS_ABI_FP_XX:
119 case MIPS_ABI_FP_64:
120 case MIPS_ABI_FP_64A:
121 return true;
122
123 default:
124 return false;
125 }
126 }
127
128 /* Return the floating point mode appropriate for the specified
129 floating point ABI. */
130
131 static int
132 fp_mode_for_abi (int abi)
133 {
134 struct mode_description *desc;
135
136 desc = &fpu_reqs[abi];
137
138 if (desc->fre)
139 return FP_FRE;
140 else if (desc->fr1)
141 return FP_FR1;
142
143 return FP_FR0;
144 }
145
146 /* Determine whether or not the CPU is capable of operating in FR0
147 floating point mode. */
148
149 bool
150 cpu_supports_fr0_p (void)
151 {
152 #if defined __mips_isa_rev && __mips_isa_rev >= 6
153 return true;
154 #else /* !defined __mips_isa_rev | mips_isa_rev < 6 */
155 return false;
156 #endif /* defined __mips_isa_rev && mips_isa_rev >= 6 */
157 }
158
159 /* Determine the FPU mode for the executable whose ELF header is
160 HEADER. If INTERPRETER is non-NULL, also take an interpreter whose
161 header is INTERPRETER into account.
162
163 ABIFLAGS should be HEADER's corresponding PT_MIPS_ABIFLAGS program
164 header, and ABIFLAGS1 should be that of INTERPRETER, if set. Both
165 fields may be NULL if no PT_MIPS_ABIFLAGS header is present; in
166 that case, use HEADER->e_flags to determine the ABI instead.
167
168 Return the FPU mode in *MODE. Value is 0 upon success, 1
169 otherwise, with errno set. */
170
171 int
172 determine_fpu_mode (elf_header *header, elf_header *interpreter,
173 int *mode, struct mips_elf_abi_flags *abiflags,
174 struct mips_elf_abi_flags *abiflags1)
175 {
176 int exec_abi, interpreter_abi;
177 struct mode_description *exec_desc, *interpreter_desc, common;
178
179 /* Figure out the executable's floating point ABI. First, consult
180 header->e_flags, and use the old 64-bit floating point ABI if it
181 is specified. */
182
183 exec_abi = MIPS_ABI_FP_ANY;
184
185 /* First, check HEADER->e_flags. */
186
187 if (header->e_flags & EF_MIPS_FP64)
188 exec_abi = MIPS_ABI_FP_OLD_64;
189
190 /* Next, use ABIFLAGS if it exists. */
191
192 if (abiflags && valid_abi_p (abiflags->fp_abi))
193 exec_abi = abiflags->fp_abi;
194 else if (abiflags)
195 {
196 errno = ENOEXEC;
197 return 1;
198 }
199
200 /* Now determine that of the interpreter. */
201
202 interpreter_abi = MIPS_ABI_FP_ANY;
203
204 if (interpreter)
205 {
206 if (interpreter->e_flags & EF_MIPS_FP64)
207 interpreter_abi = MIPS_ABI_FP_OLD_64;
208
209 if (abiflags1 && valid_abi_p (abiflags->fp_abi))
210 interpreter_abi = abiflags->fp_abi;
211 else if (abiflags1)
212 {
213 errno = ELIBBAD;
214 return 1;
215 }
216 }
217
218 /* If no interpreter flag is set, just return that of the
219 executable. */
220
221 if (!interpreter)
222 {
223 *mode = fp_mode_for_abi (exec_abi);
224 return 0;
225 }
226
227 /* Otherwise, compare both ABIs and try to find one which will run
228 both kinds of code.
229
230 First, see if there's an easy way out: both ABIs are identical,
231 or one ABI is MIPS_ABI_FP_ANY. */
232
233 if (exec_abi == interpreter_abi)
234 {
235 *mode = fp_mode_for_abi (exec_abi);
236 return 0;
237 }
238 else if (exec_abi == MIPS_ABI_FP_ANY)
239 {
240 *mode = fp_mode_for_abi (interpreter_abi);
241 return 0;
242 }
243 else if (interpreter_abi == MIPS_ABI_FP_ANY)
244 {
245 *mode = fp_mode_for_abi (exec_abi);
246 return 0;
247 }
248
249 /* If that doesn't work, compare various characteristics of both
250 ABIs and select an appropriate floating point mode. */
251
252 exec_desc = &fpu_reqs[exec_abi];
253 interpreter_desc = &fpu_reqs[interpreter_abi];
254
255 /* Merge both sets of requirements. */
256 common.single = exec_desc->single && interpreter_desc->single;
257 common.soft = exec_desc->soft && interpreter_desc->soft;
258 common.fr1 = exec_desc->fr1 && interpreter_desc->fr1;
259 common.frdefault = exec_desc->frdefault && interpreter_desc->frdefault;
260 common.fre = exec_desc->fre && interpreter_desc->fre;
261
262 /* Default to a mode capable of running code expecting 32-bit
263 registers. */
264
265 if (!(header->e_flags & EF_MIPS_ABI2))
266 *mode = FP_FR0;
267 else
268 /* But in this case, use FR1. */
269 *mode = FP_FR1;
270
271 if (common.fre && !common.frdefault && !common.fr1)
272 /* Floating point emulation mode is required. */
273 *mode = FP_FRE;
274 else if ((common.fr1 && common.frdefault)
275 || (common.single && !common.frdefault)
276 || common.fr1)
277 /* 64-bit mode is required. */
278 *mode = FP_FR1;
279 else if (!common.fre && !common.frdefault
280 && !common.fr1 && !common.single
281 && !common.soft)
282 {
283 /* The floating point modes specified are incompatible. */
284 errno = ELIBBAD;
285 return -1;
286 }
287
288 return 0;
289 }