1 | /* Copyright (C) 2014-2022 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | #include <sys/prctl.h> |
19 | #include <dlfcn.h> |
20 | #include <stdio.h> |
21 | #include <string.h> |
22 | #include <stdbool.h> |
23 | #include <errno.h> |
24 | |
25 | #if defined PR_GET_FP_MODE && defined PR_SET_FP_MODE |
26 | # define HAVE_PRCTL_FP_MODE 1 |
27 | # define FR1_MODE (PR_FP_MODE_FR) |
28 | # define FRE_MODE (PR_FP_MODE_FR | PR_FP_MODE_FRE) |
29 | #else |
30 | # define HAVE_PRCTL_FP_MODE 0 |
31 | # define FR1_MODE 0x1 |
32 | # define FRE_MODE 0x2 |
33 | #endif |
34 | |
35 | #define STR_VAL(VAL) #VAL |
36 | #define N_STR(VAL) STR_VAL(VAL) |
37 | |
38 | #define START_STATE(NAME) \ |
39 | case s_ ## NAME: \ |
40 | { \ |
41 | switch (obj) \ |
42 | { |
43 | |
44 | #define END_STATE \ |
45 | default: \ |
46 | return false; \ |
47 | } \ |
48 | break; \ |
49 | } |
50 | |
51 | #define NEXT(OBJ, NEXT_STATE) \ |
52 | case o_ ## OBJ: \ |
53 | current_fp_state = s_ ## NEXT_STATE; \ |
54 | break; |
55 | |
56 | #define NEXT_REQ_FR1(OBJ, NEXT_STATE) \ |
57 | case o_ ## OBJ: \ |
58 | { \ |
59 | if (has_fr1) \ |
60 | current_fp_state = s_ ## NEXT_STATE; \ |
61 | else \ |
62 | return false; \ |
63 | } \ |
64 | break; |
65 | |
66 | #define NEXT_REQ_FR0(OBJ, NEXT_STATE) \ |
67 | case o_ ## OBJ: \ |
68 | { \ |
69 | if (!is_r6 \ |
70 | || (is_r6 && has_fr1 && has_fre)) \ |
71 | current_fp_state = s_ ## NEXT_STATE; \ |
72 | else \ |
73 | return false; \ |
74 | } \ |
75 | break; |
76 | |
77 | #define NEXT_REQ_FRE(OBJ, NEXT_STATE) \ |
78 | case o_ ## OBJ: \ |
79 | { \ |
80 | if (has_fr1 && has_fre) \ |
81 | current_fp_state = s_ ## NEXT_STATE; \ |
82 | else \ |
83 | return false; \ |
84 | } \ |
85 | break; |
86 | |
87 | #define NEXT_NO_MODE_CHANGE(OBJ, NEXT_STATE) \ |
88 | case o_ ## OBJ: \ |
89 | { \ |
90 | if (current_mode_valid_p (s_ ## NEXT_STATE)) \ |
91 | { \ |
92 | current_fp_state = s_ ## NEXT_STATE; \ |
93 | cant_change_mode = true; \ |
94 | } \ |
95 | else \ |
96 | return false; \ |
97 | } \ |
98 | break; |
99 | |
100 | static const char * const shared_lib_names[] = |
101 | { |
102 | "tst-abi-fpanymod.so" , "tst-abi-fpsoftmod.so" , "tst-abi-fpsinglemod.so" , |
103 | "tst-abi-fp32mod.so" , "tst-abi-fp64mod.so" , "tst-abi-fp64amod.so" , |
104 | "tst-abi-fpxxmod.so" , "tst-abi-fpxxomod.so" |
105 | }; |
106 | |
107 | struct fp_mode_req |
108 | { |
109 | int mode1; |
110 | int mode2; |
111 | int mode3; |
112 | }; |
113 | |
114 | enum fp_obj |
115 | { |
116 | o_any, |
117 | o_soft, |
118 | o_single, |
119 | o_fp32, |
120 | o_fp64, |
121 | o_fp64a, |
122 | o_fpxx, |
123 | o_fpxxo, |
124 | o_max |
125 | }; |
126 | |
127 | enum fp_state |
128 | { |
129 | s_any, |
130 | s_soft, |
131 | s_single, |
132 | s_fp32, |
133 | s_fpxx, |
134 | s_fpxxo, |
135 | s_fp64a, |
136 | s_fp64, |
137 | s_fpxxo_fpxx, |
138 | s_fp32_fpxx, |
139 | s_fp32_fpxxo, |
140 | s_fp32_fpxxo_fpxx, |
141 | s_fp32_fp64a_fpxx, |
142 | s_fp32_fp64a_fpxxo, |
143 | s_fp32_fp64a_fpxxo_fpxx, |
144 | s_fp64a_fp32, |
145 | s_fp64a_fpxx, |
146 | s_fp64a_fpxxo, |
147 | s_fp64a_fp64, |
148 | s_fp64a_fp64_fpxx, |
149 | s_fp64a_fp64_fpxxo, |
150 | s_fp64a_fpxx_fpxxo, |
151 | s_fp64a_fp64_fpxxo_fpxx, |
152 | s_fp64_fpxx, |
153 | s_fp64_fpxxo, |
154 | s_fp64_fpxx_fpxxo |
155 | }; |
156 | |
157 | |
158 | static int current_fp_mode; |
159 | static bool cant_change_mode = false; |
160 | static bool has_fr1 = false; |
161 | static bool has_fre = false; |
162 | static bool is_r6 = false; |
163 | static unsigned int fp_obj_count[o_max]; |
164 | void * shared_lib_ptrs[o_max]; |
165 | static enum fp_state current_fp_state = s_any; |
166 | static enum fp_obj test_objects[FPABI_COUNT] = { FPABI_LIST }; |
167 | |
168 | /* This function will return the valid FP modes for the specified state. */ |
169 | |
170 | static struct fp_mode_req |
171 | compute_fp_modes (enum fp_state state) |
172 | { |
173 | struct fp_mode_req requirements; |
174 | |
175 | requirements.mode1 = -1; |
176 | requirements.mode2 = -1; |
177 | requirements.mode3 = -1; |
178 | |
179 | switch (state) |
180 | { |
181 | case s_single: |
182 | { |
183 | if (is_r6) |
184 | requirements.mode1 = FR1_MODE; |
185 | else |
186 | { |
187 | requirements.mode1 = 0; |
188 | requirements.mode2 = FR1_MODE; |
189 | } |
190 | break; |
191 | } |
192 | case s_fp32: |
193 | case s_fp32_fpxx: |
194 | case s_fp32_fpxxo: |
195 | case s_fp32_fpxxo_fpxx: |
196 | { |
197 | if (is_r6) |
198 | requirements.mode1 = FRE_MODE; |
199 | else |
200 | { |
201 | requirements.mode1 = 0; |
202 | requirements.mode2 = FRE_MODE; |
203 | } |
204 | break; |
205 | } |
206 | case s_fpxx: |
207 | case s_fpxxo: |
208 | case s_fpxxo_fpxx: |
209 | case s_any: |
210 | case s_soft: |
211 | { |
212 | if (is_r6) |
213 | { |
214 | requirements.mode1 = FR1_MODE; |
215 | requirements.mode2 = FRE_MODE; |
216 | } |
217 | else |
218 | { |
219 | requirements.mode1 = 0; |
220 | requirements.mode2 = FR1_MODE; |
221 | requirements.mode3 = FRE_MODE; |
222 | } |
223 | break; |
224 | } |
225 | case s_fp64a: |
226 | case s_fp64a_fpxx: |
227 | case s_fp64a_fpxxo: |
228 | case s_fp64a_fpxx_fpxxo: |
229 | { |
230 | requirements.mode1 = FR1_MODE; |
231 | requirements.mode2 = FRE_MODE; |
232 | break; |
233 | } |
234 | case s_fp64: |
235 | case s_fp64_fpxx: |
236 | case s_fp64_fpxxo: |
237 | case s_fp64_fpxx_fpxxo: |
238 | case s_fp64a_fp64: |
239 | case s_fp64a_fp64_fpxx: |
240 | case s_fp64a_fp64_fpxxo: |
241 | case s_fp64a_fp64_fpxxo_fpxx: |
242 | { |
243 | requirements.mode1 = FR1_MODE; |
244 | break; |
245 | } |
246 | case s_fp64a_fp32: |
247 | case s_fp32_fp64a_fpxx: |
248 | case s_fp32_fp64a_fpxxo: |
249 | case s_fp32_fp64a_fpxxo_fpxx: |
250 | { |
251 | requirements.mode1 = FRE_MODE; |
252 | break; |
253 | } |
254 | } |
255 | return requirements; |
256 | } |
257 | |
258 | /* Check the current mode is suitable for the specified state. */ |
259 | |
260 | static bool |
261 | current_mode_valid_p (enum fp_state s) |
262 | { |
263 | struct fp_mode_req req = compute_fp_modes (state: s); |
264 | return (req.mode1 == current_fp_mode |
265 | || req.mode2 == current_fp_mode |
266 | || req.mode3 == current_fp_mode); |
267 | } |
268 | |
269 | /* Run the state machine by adding a new object. */ |
270 | |
271 | static bool |
272 | set_next_fp_state (enum fp_obj obj) |
273 | { |
274 | cant_change_mode = false; |
275 | switch (current_fp_state) |
276 | { |
277 | |
278 | START_STATE(soft) |
279 | NEXT(soft,soft) |
280 | NEXT(any,soft) |
281 | END_STATE |
282 | |
283 | START_STATE(single) |
284 | NEXT(single,single) |
285 | NEXT(any,single) |
286 | END_STATE |
287 | |
288 | START_STATE(any) |
289 | NEXT_REQ_FR0(fp32, fp32) |
290 | NEXT(fpxx, fpxx) |
291 | NEXT(fpxxo, fpxxo) |
292 | NEXT_REQ_FR1(fp64a, fp64a) |
293 | NEXT_REQ_FR1(fp64, fp64) |
294 | NEXT(any,any) |
295 | NEXT(soft,soft) |
296 | NEXT(single,single) |
297 | END_STATE |
298 | |
299 | START_STATE(fp32) |
300 | NEXT_REQ_FR0(fp32,fp32) |
301 | NEXT(fpxx, fp32_fpxx) |
302 | NEXT(fpxxo, fp32_fpxxo) |
303 | NEXT_REQ_FRE(fp64a, fp64a_fp32) |
304 | NEXT(any,fp32) |
305 | END_STATE |
306 | |
307 | START_STATE(fpxx) |
308 | NEXT_REQ_FR0(fp32, fp32_fpxx) |
309 | NEXT_REQ_FR1(fp64, fp64_fpxx) |
310 | NEXT_REQ_FR1(fp64a, fp64a_fpxx) |
311 | NEXT(fpxxo, fpxxo_fpxx) |
312 | NEXT(fpxx,fpxx) |
313 | NEXT(any,fpxx) |
314 | END_STATE |
315 | |
316 | START_STATE(fpxxo) |
317 | NEXT_NO_MODE_CHANGE(fp32, fp32_fpxxo) |
318 | NEXT_NO_MODE_CHANGE(fp64, fp64_fpxxo) |
319 | NEXT_NO_MODE_CHANGE(fp64a, fp64a_fpxxo) |
320 | NEXT_NO_MODE_CHANGE(fpxx, fpxxo_fpxx) |
321 | NEXT_NO_MODE_CHANGE(fpxxo,fpxxo) |
322 | NEXT_NO_MODE_CHANGE(any,fpxxo) |
323 | END_STATE |
324 | |
325 | START_STATE(fp64a) |
326 | NEXT_REQ_FRE(fp32, fp64a_fp32) |
327 | NEXT_REQ_FR1(fp64, fp64a_fp64) |
328 | NEXT(fpxxo, fp64a_fpxxo) |
329 | NEXT(fpxx, fp64a_fpxx) |
330 | NEXT_REQ_FR1(fp64a, fp64a) |
331 | NEXT(any, fp64a) |
332 | END_STATE |
333 | |
334 | START_STATE(fp64) |
335 | NEXT_REQ_FR1(fp64a, fp64a_fp64) |
336 | NEXT(fpxxo, fp64_fpxxo) |
337 | NEXT(fpxx, fp64_fpxx) |
338 | NEXT_REQ_FR1(fp64, fp64) |
339 | NEXT(any, fp64) |
340 | END_STATE |
341 | |
342 | START_STATE(fpxxo_fpxx) |
343 | NEXT_NO_MODE_CHANGE(fp32, fp32_fpxxo_fpxx) |
344 | NEXT_NO_MODE_CHANGE(fp64, fp64_fpxx_fpxxo) |
345 | NEXT_NO_MODE_CHANGE(fp64a, fp64a_fpxx_fpxxo) |
346 | NEXT_NO_MODE_CHANGE(fpxx, fpxxo_fpxx) |
347 | NEXT_NO_MODE_CHANGE(fpxxo, fpxxo_fpxx) |
348 | NEXT_NO_MODE_CHANGE(any, fpxxo_fpxx) |
349 | END_STATE |
350 | |
351 | START_STATE(fp32_fpxx) |
352 | NEXT_REQ_FR0(fp32, fp32_fpxx) |
353 | NEXT(fpxx, fp32_fpxx) |
354 | NEXT(fpxxo, fp32_fpxxo_fpxx) |
355 | NEXT_REQ_FRE(fp64a, fp32_fp64a_fpxx) |
356 | NEXT(any, fp32_fpxx) |
357 | END_STATE |
358 | |
359 | START_STATE(fp32_fpxxo) |
360 | NEXT_NO_MODE_CHANGE(fp32, fp32_fpxxo) |
361 | NEXT_NO_MODE_CHANGE(fpxxo, fp32_fpxxo) |
362 | NEXT_NO_MODE_CHANGE(fpxx, fp32_fpxxo_fpxx) |
363 | NEXT_NO_MODE_CHANGE(fp64a, fp32_fp64a_fpxxo) |
364 | NEXT_NO_MODE_CHANGE(any, fp32_fpxxo) |
365 | END_STATE |
366 | |
367 | START_STATE(fp32_fpxxo_fpxx) |
368 | NEXT_NO_MODE_CHANGE(fp32, fp32_fpxxo_fpxx) |
369 | NEXT_NO_MODE_CHANGE(fpxxo, fp32_fpxxo_fpxx) |
370 | NEXT_NO_MODE_CHANGE(fpxx, fp32_fpxxo_fpxx) |
371 | NEXT_NO_MODE_CHANGE(fp64a, fp32_fp64a_fpxxo_fpxx) |
372 | NEXT_NO_MODE_CHANGE(any, fp32_fpxxo_fpxx) |
373 | END_STATE |
374 | |
375 | START_STATE(fp64a_fp32) |
376 | NEXT_REQ_FRE(fp32, fp64a_fp32) |
377 | NEXT_REQ_FRE(fp64a, fp64a_fp32) |
378 | NEXT(fpxxo, fp32_fp64a_fpxxo) |
379 | NEXT(fpxx, fp32_fp64a_fpxx) |
380 | NEXT(any, fp64a_fp32) |
381 | END_STATE |
382 | |
383 | START_STATE(fp64a_fpxx) |
384 | NEXT_REQ_FRE(fp32, fp32_fp64a_fpxx) |
385 | NEXT_REQ_FR1(fp64a, fp64a_fpxx) |
386 | NEXT(fpxx, fp64a_fpxx) |
387 | NEXT(fpxxo, fp64a_fpxx_fpxxo) |
388 | NEXT_REQ_FR1(fp64, fp64a_fp64_fpxx) |
389 | NEXT(any, fp64a_fpxx) |
390 | END_STATE |
391 | |
392 | START_STATE(fp64a_fpxxo) |
393 | NEXT_NO_MODE_CHANGE(fp32, fp32_fp64a_fpxxo) |
394 | NEXT_NO_MODE_CHANGE(fp64a, fp64a_fpxxo) |
395 | NEXT_NO_MODE_CHANGE(fpxx, fp64a_fpxx_fpxxo) |
396 | NEXT_NO_MODE_CHANGE(fpxxo, fp64a_fpxxo) |
397 | NEXT_NO_MODE_CHANGE(fp64, fp64a_fp64_fpxxo) |
398 | NEXT_NO_MODE_CHANGE(any, fp64a_fpxxo) |
399 | END_STATE |
400 | |
401 | START_STATE(fp64a_fpxx_fpxxo) |
402 | NEXT_NO_MODE_CHANGE(fp32, fp32_fp64a_fpxxo_fpxx) |
403 | NEXT_NO_MODE_CHANGE(fp64a, fp64a_fpxx_fpxxo) |
404 | NEXT_NO_MODE_CHANGE(fpxx, fp64a_fpxx_fpxxo) |
405 | NEXT_NO_MODE_CHANGE(fpxxo, fp64a_fpxx_fpxxo) |
406 | NEXT_NO_MODE_CHANGE(fp64, fp64a_fp64_fpxxo_fpxx) |
407 | NEXT_NO_MODE_CHANGE(any, fp64a_fpxx_fpxxo) |
408 | END_STATE |
409 | |
410 | START_STATE(fp64_fpxx) |
411 | NEXT_REQ_FR1(fp64a, fp64a_fp64_fpxx) |
412 | NEXT(fpxxo, fp64_fpxx_fpxxo) |
413 | NEXT(fpxx, fp64_fpxx) |
414 | NEXT_REQ_FR1(fp64, fp64_fpxx) |
415 | NEXT(any, fp64_fpxx) |
416 | END_STATE |
417 | |
418 | START_STATE(fp64_fpxxo) |
419 | NEXT_NO_MODE_CHANGE(fp64a, fp64a_fp64_fpxxo) |
420 | NEXT_NO_MODE_CHANGE(fpxxo, fp64_fpxxo) |
421 | NEXT_NO_MODE_CHANGE(fpxx, fp64_fpxx_fpxxo) |
422 | NEXT_NO_MODE_CHANGE(fp64, fp64_fpxxo) |
423 | NEXT_NO_MODE_CHANGE(any, fp64_fpxxo) |
424 | END_STATE |
425 | |
426 | START_STATE(fp64_fpxx_fpxxo) |
427 | NEXT_NO_MODE_CHANGE(fp64a, fp64a_fp64_fpxxo_fpxx) |
428 | NEXT_NO_MODE_CHANGE(fpxxo, fp64_fpxx_fpxxo) |
429 | NEXT_NO_MODE_CHANGE(fpxx, fp64_fpxx_fpxxo) |
430 | NEXT_NO_MODE_CHANGE(fp64, fp64_fpxx_fpxxo) |
431 | NEXT_NO_MODE_CHANGE(any, fp64_fpxx_fpxxo) |
432 | END_STATE |
433 | |
434 | START_STATE(fp64a_fp64) |
435 | NEXT_REQ_FR1(fp64a, fp64a_fp64) |
436 | NEXT(fpxxo, fp64a_fp64_fpxxo) |
437 | NEXT(fpxx, fp64a_fp64_fpxx) |
438 | NEXT_REQ_FR1(fp64, fp64a_fp64) |
439 | NEXT(any, fp64a_fp64) |
440 | END_STATE |
441 | |
442 | START_STATE(fp64a_fp64_fpxx) |
443 | NEXT_REQ_FR1(fp64a, fp64a_fp64_fpxx) |
444 | NEXT(fpxxo, fp64a_fp64_fpxxo_fpxx) |
445 | NEXT(fpxx, fp64a_fp64_fpxx) |
446 | NEXT_REQ_FR1(fp64, fp64a_fp64_fpxx) |
447 | NEXT(any, fp64a_fp64_fpxx) |
448 | END_STATE |
449 | |
450 | START_STATE(fp64a_fp64_fpxxo) |
451 | NEXT_NO_MODE_CHANGE(fp64a, fp64a_fp64_fpxxo) |
452 | NEXT_NO_MODE_CHANGE(fpxx, fp64a_fp64_fpxxo_fpxx) |
453 | NEXT_NO_MODE_CHANGE(fpxxo, fp64a_fp64_fpxxo) |
454 | NEXT_NO_MODE_CHANGE(fp64, fp64a_fp64_fpxxo) |
455 | NEXT_NO_MODE_CHANGE(any, fp64a_fp64_fpxxo) |
456 | END_STATE |
457 | |
458 | START_STATE(fp64a_fp64_fpxxo_fpxx) |
459 | NEXT_NO_MODE_CHANGE(fp64a, fp64a_fp64_fpxxo_fpxx) |
460 | NEXT_NO_MODE_CHANGE(fpxx, fp64a_fp64_fpxxo_fpxx) |
461 | NEXT_NO_MODE_CHANGE(fpxxo, fp64a_fp64_fpxxo_fpxx) |
462 | NEXT_NO_MODE_CHANGE(fp64, fp64a_fp64_fpxxo_fpxx) |
463 | NEXT_NO_MODE_CHANGE(any, fp64a_fp64_fpxxo_fpxx) |
464 | END_STATE |
465 | |
466 | START_STATE(fp32_fp64a_fpxx) |
467 | NEXT_REQ_FRE(fp32, fp32_fp64a_fpxx) |
468 | NEXT_REQ_FRE(fp64a, fp32_fp64a_fpxx) |
469 | NEXT(fpxxo, fp32_fp64a_fpxxo_fpxx) |
470 | NEXT(fpxx, fp32_fp64a_fpxx) |
471 | NEXT(any, fp32_fp64a_fpxx) |
472 | END_STATE |
473 | |
474 | START_STATE(fp32_fp64a_fpxxo) |
475 | NEXT_NO_MODE_CHANGE(fp32, fp32_fp64a_fpxxo) |
476 | NEXT_NO_MODE_CHANGE(fp64a, fp32_fp64a_fpxxo) |
477 | NEXT_NO_MODE_CHANGE(fpxx, fp32_fp64a_fpxxo_fpxx) |
478 | NEXT_NO_MODE_CHANGE(fpxxo, fp32_fp64a_fpxxo) |
479 | NEXT_NO_MODE_CHANGE(any, fp32_fp64a_fpxxo) |
480 | END_STATE |
481 | |
482 | START_STATE(fp32_fp64a_fpxxo_fpxx) |
483 | NEXT_NO_MODE_CHANGE(fp32, fp32_fp64a_fpxxo_fpxx) |
484 | NEXT_NO_MODE_CHANGE(fp64a, fp32_fp64a_fpxxo_fpxx) |
485 | NEXT_NO_MODE_CHANGE(fpxx, fp32_fp64a_fpxxo_fpxx) |
486 | NEXT_NO_MODE_CHANGE(fpxxo, fp32_fp64a_fpxxo_fpxx) |
487 | NEXT_NO_MODE_CHANGE(any, fp32_fp64a_fpxxo_fpxx) |
488 | END_STATE |
489 | } |
490 | |
491 | if (obj != o_max) |
492 | fp_obj_count[obj]++; |
493 | |
494 | return true; |
495 | } |
496 | |
497 | /* Run the state machine by removing an object. */ |
498 | |
499 | static bool |
500 | remove_object (enum fp_obj obj) |
501 | { |
502 | if (obj == o_max) |
503 | return false; |
504 | |
505 | fp_obj_count[obj]--; |
506 | |
507 | /* We can't change fp state until all the objects |
508 | of a particular type have been unloaded. */ |
509 | if (fp_obj_count[obj] != 0) |
510 | return false; |
511 | |
512 | switch (current_fp_state) |
513 | { |
514 | START_STATE(soft) |
515 | NEXT(soft,any) |
516 | END_STATE |
517 | |
518 | START_STATE(single) |
519 | NEXT(single,any) |
520 | END_STATE |
521 | |
522 | START_STATE(any) |
523 | NEXT(any,any) |
524 | END_STATE |
525 | |
526 | START_STATE(fp32) |
527 | NEXT (fp32,any) |
528 | END_STATE |
529 | |
530 | START_STATE(fpxx) |
531 | NEXT (fpxx,any) |
532 | END_STATE |
533 | |
534 | START_STATE(fpxxo) |
535 | NEXT (fpxxo,any) |
536 | END_STATE |
537 | |
538 | START_STATE(fp64a) |
539 | NEXT(fp64a, any) |
540 | END_STATE |
541 | |
542 | START_STATE(fp64) |
543 | NEXT(fp64, any) |
544 | END_STATE |
545 | |
546 | START_STATE(fpxxo_fpxx) |
547 | NEXT(fpxx, fpxxo) |
548 | NEXT(fpxxo, fpxx) |
549 | END_STATE |
550 | |
551 | START_STATE(fp32_fpxx) |
552 | NEXT(fp32, fpxx) |
553 | NEXT(fpxx, fp32) |
554 | END_STATE |
555 | |
556 | START_STATE(fp32_fpxxo) |
557 | NEXT(fp32, fpxxo) |
558 | NEXT(fpxxo, fp32) |
559 | END_STATE |
560 | |
561 | START_STATE(fp32_fpxxo_fpxx) |
562 | NEXT(fp32, fpxxo_fpxx) |
563 | NEXT(fpxxo, fp32_fpxx) |
564 | NEXT(fpxx, fp32_fpxxo) |
565 | END_STATE |
566 | |
567 | START_STATE(fp64a_fp32) |
568 | NEXT(fp32, fp64a) |
569 | NEXT(fp64a, fp32) |
570 | END_STATE |
571 | |
572 | START_STATE(fp64a_fpxx) |
573 | NEXT(fp64a, fpxx) |
574 | NEXT(fpxx, fp64a) |
575 | END_STATE |
576 | |
577 | START_STATE(fp64a_fpxxo) |
578 | NEXT(fp64a, fpxxo) |
579 | NEXT(fpxxo, fp64a) |
580 | END_STATE |
581 | |
582 | START_STATE(fp64a_fpxx_fpxxo) |
583 | NEXT(fp64a, fpxxo_fpxx) |
584 | NEXT(fpxx, fp64a_fpxxo) |
585 | NEXT(fpxxo, fp64a_fpxx) |
586 | END_STATE |
587 | |
588 | START_STATE(fp64_fpxx) |
589 | NEXT(fpxx, fp64) |
590 | NEXT(fp64, fpxx) |
591 | END_STATE |
592 | |
593 | START_STATE(fp64_fpxxo) |
594 | NEXT(fpxxo, fp64) |
595 | NEXT(fp64, fpxxo) |
596 | END_STATE |
597 | |
598 | START_STATE(fp64_fpxx_fpxxo) |
599 | NEXT(fp64, fpxxo_fpxx) |
600 | NEXT(fpxxo, fp64_fpxx) |
601 | NEXT(fpxx, fp64_fpxxo) |
602 | END_STATE |
603 | |
604 | START_STATE(fp64a_fp64) |
605 | NEXT(fp64a, fp64) |
606 | NEXT(fp64, fp64a) |
607 | END_STATE |
608 | |
609 | START_STATE(fp64a_fp64_fpxx) |
610 | NEXT(fp64a, fp64_fpxx) |
611 | NEXT(fpxx, fp64a_fp64) |
612 | NEXT(fp64, fp64a_fpxx) |
613 | END_STATE |
614 | |
615 | START_STATE(fp64a_fp64_fpxxo) |
616 | NEXT(fp64a, fp64_fpxxo) |
617 | NEXT(fpxxo, fp64a_fp64) |
618 | NEXT(fp64, fp64a_fpxxo) |
619 | END_STATE |
620 | |
621 | START_STATE(fp64a_fp64_fpxxo_fpxx) |
622 | NEXT(fp64a, fp64_fpxx_fpxxo) |
623 | NEXT(fpxx, fp64a_fp64_fpxxo) |
624 | NEXT(fpxxo, fp64a_fp64_fpxx) |
625 | NEXT(fp64, fp64a_fpxx_fpxxo) |
626 | END_STATE |
627 | |
628 | START_STATE(fp32_fp64a_fpxx) |
629 | NEXT(fp32, fp64a_fpxx) |
630 | NEXT(fp64a, fp32_fpxx) |
631 | NEXT(fpxx, fp64a_fp32) |
632 | END_STATE |
633 | |
634 | START_STATE(fp32_fp64a_fpxxo) |
635 | NEXT(fp32, fp64a_fpxxo) |
636 | NEXT(fp64a, fp32_fpxxo) |
637 | NEXT(fpxxo, fp64a_fp32) |
638 | END_STATE |
639 | |
640 | START_STATE(fp32_fp64a_fpxxo_fpxx) |
641 | NEXT(fp32, fp64a_fpxx_fpxxo) |
642 | NEXT(fp64a, fp32_fpxxo_fpxx) |
643 | NEXT(fpxx, fp32_fp64a_fpxxo) |
644 | NEXT(fpxxo, fp32_fp64a_fpxx) |
645 | END_STATE |
646 | } |
647 | |
648 | return true; |
649 | } |
650 | |
651 | static int |
652 | mode_transition_valid_p (void) |
653 | { |
654 | int prev_fp_mode; |
655 | |
656 | /* Get the current fp mode. */ |
657 | prev_fp_mode = current_fp_mode; |
658 | #if HAVE_PRCTL_FP_MODE |
659 | current_fp_mode = prctl (PR_GET_FP_MODE); |
660 | |
661 | /* If the prctl call fails assume the core only has FR0 mode support. */ |
662 | if (current_fp_mode == -1) |
663 | current_fp_mode = 0; |
664 | #endif |
665 | |
666 | if (!current_mode_valid_p (s: current_fp_state)) |
667 | return 0; |
668 | |
669 | /* Check if mode changes are not allowed but a mode change happened. */ |
670 | if (cant_change_mode |
671 | && current_fp_mode != prev_fp_mode) |
672 | return 0; |
673 | |
674 | return 1; |
675 | } |
676 | |
677 | /* Load OBJ and check that it was/was not loaded correctly. */ |
678 | bool |
679 | load_object (enum fp_obj obj) |
680 | { |
681 | bool should_load = set_next_fp_state (obj); |
682 | |
683 | shared_lib_ptrs[obj] = dlopen (file: shared_lib_names[obj], RTLD_LAZY); |
684 | |
685 | /* If we expected an error and the load was successful then fail. */ |
686 | if (!should_load && (shared_lib_ptrs[obj] != 0)) |
687 | return false; |
688 | |
689 | if (should_load && (shared_lib_ptrs[obj] == 0)) |
690 | return false; |
691 | |
692 | if (!mode_transition_valid_p ()) |
693 | return false; |
694 | |
695 | return true; |
696 | } |
697 | |
698 | /* Remove an object and check the state remains valid. */ |
699 | bool |
700 | unload_object (enum fp_obj obj) |
701 | { |
702 | if (!shared_lib_ptrs[obj]) |
703 | return true; |
704 | |
705 | remove_object (obj); |
706 | |
707 | if (dlclose (handle: shared_lib_ptrs[obj]) != 0) |
708 | return false; |
709 | |
710 | shared_lib_ptrs[obj] = 0; |
711 | |
712 | if (!mode_transition_valid_p ()) |
713 | return false; |
714 | |
715 | return true; |
716 | } |
717 | |
718 | /* Load every permuation of OBJECTS. */ |
719 | static bool |
720 | test_permutations (enum fp_obj objects[], int count) |
721 | { |
722 | int i; |
723 | |
724 | for (i = 0 ; i < count ; i++) |
725 | { |
726 | if (!load_object (obj: objects[i])) |
727 | return false; |
728 | |
729 | if (count > 1) |
730 | { |
731 | enum fp_obj new_objects[count - 1]; |
732 | int j; |
733 | int k = 0; |
734 | |
735 | for (j = 0 ; j < count ; j++) |
736 | { |
737 | if (j != i) |
738 | new_objects[k++] = objects[j]; |
739 | } |
740 | |
741 | if (!test_permutations (objects: new_objects, count: count - 1)) |
742 | return false; |
743 | } |
744 | |
745 | if (!unload_object (obj: objects[i])) |
746 | return false; |
747 | } |
748 | return true; |
749 | } |
750 | |
751 | int |
752 | do_test (void) |
753 | { |
754 | #if HAVE_PRCTL_FP_MODE |
755 | /* Determine available hardware support and current mode. */ |
756 | current_fp_mode = prctl (PR_GET_FP_MODE); |
757 | |
758 | /* If the prctl call fails assume the core only has FR0 mode support. */ |
759 | if (current_fp_mode == -1) |
760 | current_fp_mode = 0; |
761 | else |
762 | { |
763 | if (prctl (PR_SET_FP_MODE, 0) != 0) |
764 | { |
765 | if (errno == ENOTSUP) |
766 | is_r6 = true; |
767 | else |
768 | { |
769 | printf (format: "unexpected error from PR_SET_FP_MODE, 0: %m\n" ); |
770 | return 1; |
771 | } |
772 | } |
773 | |
774 | if (prctl (PR_SET_FP_MODE, PR_FP_MODE_FR) != 0) |
775 | { |
776 | if (errno != ENOTSUP) |
777 | { |
778 | printf (format: "unexpected error from PR_SET_FP_MODE, " |
779 | "PR_FP_MODE_FR: %m\n" ); |
780 | return 1; |
781 | } |
782 | } |
783 | else |
784 | has_fr1 = true; |
785 | |
786 | if (prctl (PR_SET_FP_MODE, PR_FP_MODE_FR | PR_FP_MODE_FRE) != 0) |
787 | { |
788 | if (errno != ENOTSUP) |
789 | { |
790 | printf (format: "unexpected error from PR_SET_FP_MODE, " |
791 | "PR_FP_MODE_FR | PR_FP_MODE_FRE: %m\n" ); |
792 | return 1; |
793 | } |
794 | } |
795 | else |
796 | has_fre = true; |
797 | |
798 | if (prctl (PR_SET_FP_MODE, current_fp_mode) != 0) |
799 | { |
800 | printf (format: "unable to restore initial FP mode: %m\n" ); |
801 | return 1; |
802 | } |
803 | } |
804 | |
805 | if ((is_r6 && !(current_fp_mode & PR_FP_MODE_FR)) |
806 | || (!has_fr1 && (current_fp_mode & PR_FP_MODE_FR)) |
807 | || (!has_fre && (current_fp_mode & PR_FP_MODE_FRE))) |
808 | { |
809 | puts (s: "Inconsistency detected between initial FP mode " |
810 | "and supported FP modes\n" ); |
811 | return 1; |
812 | } |
813 | #else |
814 | current_fp_mode = 0; |
815 | #endif |
816 | |
817 | /* Set up the initial state from executable and LDSO. Assumptions: |
818 | 1) All system libraries have the same ABI as ld.so. |
819 | 2) Due to the fact that ld.so is tested by invoking it directly |
820 | rather than via an interpreter, there is no point in varying |
821 | the ABI of the test program. Instead the ABI only varies for |
822 | the shared libraries which get loaded. */ |
823 | if (!set_next_fp_state (FPABI_NATIVE)) |
824 | { |
825 | puts (s: "Unable to enter initial ABI state\n" ); |
826 | return 1; |
827 | } |
828 | |
829 | /* Compare the computed state with the hardware state. */ |
830 | if (!mode_transition_valid_p ()) |
831 | return 1; |
832 | |
833 | /* Run all possible test permutations. */ |
834 | if (!test_permutations (objects: test_objects, count: FPABI_COUNT)) |
835 | { |
836 | puts (s: "Mode checks failed\n" ); |
837 | return 1; |
838 | } |
839 | |
840 | return 0; |
841 | } |
842 | |
843 | #define TEST_FUNCTION do_test () |
844 | #include "../../test-skeleton.c" |
845 | |