]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/powerpc/fpu/tst-setcontext-fpscr.c
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / sysdeps / powerpc / fpu / tst-setcontext-fpscr.c
1 /* Copyright (C) 2001-2019 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ryan S. Arnold <rsa@us.ibm.com>
4 Sean Curry <spcurry@us.ibm.com>
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <https://www.gnu.org/licenses/>. */
19
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ucontext.h>
25 #include <unistd.h>
26 #include <link.h>
27 #include <elf.h>
28 #include <fpu_control.h>
29 #include <sys/auxv.h>
30 #include <support/support.h>
31
32 static ucontext_t ctx[3];
33
34
35 volatile int global;
36
37
38 static int back_in_main;
39
40
41 volatile static ElfW(auxv_t) *auxv = NULL;
42
43 ElfW(Addr) query_auxv(int type)
44 {
45 FILE *auxv_f;
46 ElfW(auxv_t) auxv_struct;
47 ElfW(auxv_t) *auxv_temp;
48 int i = 0;
49
50 /* if the /proc/self/auxv file has not been manually copied into the heap
51 yet, then do it */
52
53 if(auxv == NULL)
54 {
55 auxv_f = fopen("/proc/self/auxv", "r");
56
57 if(auxv_f == 0)
58 {
59 perror("Error opening file for reading");
60 return 0;
61 }
62 auxv = xmalloc (getpagesize ());
63
64 do
65 {
66 fread (&auxv_struct, sizeof (ElfW(auxv_t)), 1, auxv_f);
67 auxv[i] = auxv_struct;
68 i++;
69 } while(auxv_struct.a_type != AT_NULL);
70 }
71
72 auxv_temp = (ElfW(auxv_t) *)auxv;
73 i = 0;
74 do
75 {
76 if(auxv_temp[i].a_type == type)
77 {
78 return auxv_temp[i].a_un.a_val;
79 }
80 i++;
81 } while (auxv_temp[i].a_type != AT_NULL);
82
83 return 0;
84 }
85
86 typedef unsigned int di_fpscr_t __attribute__ ((__mode__ (__DI__)));
87 typedef unsigned int si_fpscr_t __attribute__ ((__mode__ (__SI__)));
88
89 #define _FPSCR_RESERVED 0xfffffff8ffffff04ULL
90
91 #define _FPSCR_TEST0_DRN 0x0000000400000000ULL
92 #define _FPSCR_TEST0_RN 0x0000000000000003ULL
93
94 #define _FPSCR_TEST1_DRN 0x0000000300000000ULL
95 #define _FPSCR_TEST1_RN 0x0000000000000002ULL
96
97 /* Macros for accessing the hardware control word on Power6[x]. */
98 #define _GET_DI_FPSCR(__fpscr) \
99 ({union { double d; di_fpscr_t fpscr; } u; \
100 u.d = __builtin_mffs (); \
101 (__fpscr) = u.fpscr; \
102 u.fpscr; \
103 })
104
105 /* We make sure to zero fp after we use it in order to prevent stale data
106 in an fp register from making a test-case pass erroneously. */
107 # define _SET_DI_FPSCR(__fpscr) \
108 { union { double d; di_fpscr_t fpscr; } u; \
109 register double fr; \
110 u.fpscr = __fpscr; \
111 fr = u.d; \
112 /* Set the entire 64-bit FPSCR. */ \
113 __asm__ (".machine push; " \
114 ".machine \"power6\"; " \
115 "mtfsf 255,%0,1,0; " \
116 ".machine pop" : : "f" (fr)); \
117 fr = 0.0; \
118 }
119
120 # define _GET_SI_FPSCR(__fpscr) \
121 ({union { double d; di_fpscr_t fpscr; } u; \
122 u.d = __builtin_mffs (); \
123 (__fpscr) = (si_fpscr_t) u.fpscr; \
124 (si_fpscr_t) u.fpscr; \
125 })
126
127 /* We make sure to zero fp after we use it in order to prevent stale data
128 in an fp register from making a test-case pass erroneously. */
129 # define _SET_SI_FPSCR(__fpscr) \
130 { union { double d; di_fpscr_t fpscr; } u; \
131 register double fr; \
132 /* More-or-less arbitrary; this is a QNaN. */ \
133 u.fpscr = 0xfff80000ULL << 32; \
134 u.fpscr |= __fpscr & 0xffffffffULL; \
135 fr = u.d; \
136 __builtin_mtfsf (255, fr); \
137 fr = 0.0; \
138 }
139
140 void prime_special_regs(int which)
141 {
142 ElfW(Addr) a_val;
143
144 di_fpscr_t di_fpscr __attribute__ ((__aligned__(8)));
145
146 a_val = query_auxv(AT_HWCAP);
147 if(a_val == -1)
148 {
149 puts ("querying the auxv for the hwcap failed");
150 _exit (1);
151 }
152
153 /* Indicates a 64-bit FPSCR. */
154 if (a_val & PPC_FEATURE_HAS_DFP)
155 {
156 _GET_DI_FPSCR(di_fpscr);
157
158 /* Overwrite the existing DRN and RN if there is one. */
159 if (which == 0)
160 di_fpscr = ((di_fpscr & _FPSCR_RESERVED) | (_FPSCR_TEST0_DRN | _FPSCR_TEST0_RN));
161 else
162 di_fpscr = ((di_fpscr & _FPSCR_RESERVED) | (_FPSCR_TEST1_DRN | _FPSCR_TEST1_RN));
163 puts ("Priming 64-bit FPSCR with:");
164 printf("0x%.16llx\n",(unsigned long long int)di_fpscr);
165
166 _SET_DI_FPSCR(di_fpscr);
167 }
168 else
169 {
170 puts ("32-bit FPSCR found and will be tested.");
171 _GET_SI_FPSCR(di_fpscr);
172
173 /* Overwrite the existing RN if there is one. */
174 if (which == 0)
175 di_fpscr = ((di_fpscr & _FPSCR_RESERVED) | (_FPSCR_TEST0_RN));
176 else
177 di_fpscr = ((di_fpscr & _FPSCR_RESERVED) | (_FPSCR_TEST1_RN));
178 puts ("Priming 32-bit FPSCR with:");
179 printf("0x%.8lx\n",(unsigned long int) di_fpscr);
180
181 _SET_SI_FPSCR(di_fpscr);
182 }
183 }
184
185 void clear_special_regs(void)
186 {
187 ElfW(Addr) a_val;
188
189 di_fpscr_t di_fpscr __attribute__ ((__aligned__(8)));
190
191 union {
192 double d;
193 unsigned long long int lli;
194 unsigned int li[2];
195 } dlli;
196
197 a_val = query_auxv(AT_HWCAP);
198 if(a_val == -1)
199 {
200 puts ("querying the auxv for the hwcap failed");
201 _exit (1);
202 }
203
204 #if __WORDSIZE == 32
205 dlli.d = ctx[0].uc_mcontext.uc_regs->fpregs.fpscr;
206 #else
207 dlli.d = ctx[0].uc_mcontext.fp_regs[32];
208 #endif
209
210 puts("The FPSCR value saved in the ucontext_t is:");
211
212 /* Indicates a 64-bit FPSCR. */
213 if (a_val & PPC_FEATURE_HAS_DFP)
214 {
215 printf("0x%.16llx\n",dlli.lli);
216 di_fpscr = 0x0;
217 puts ("Clearing the 64-bit FPSCR to:");
218 printf("0x%.16llx\n",(unsigned long long int) di_fpscr);
219
220 _SET_DI_FPSCR(di_fpscr);
221 }
222 else
223 {
224 printf("0x%.8x\n",(unsigned int) dlli.li[1]);
225 di_fpscr = 0x0;
226 puts ("Clearing the 32-bit FPSCR to:");
227 printf("0x%.8lx\n",(unsigned long int) di_fpscr);
228
229 _SET_SI_FPSCR(di_fpscr);
230 }
231 }
232
233 void test_special_regs(int which)
234 {
235 ElfW(Addr) a_val;
236 unsigned long long int test;
237
238 di_fpscr_t di_fpscr __attribute__ ((__aligned__(8)));
239
240 a_val = query_auxv(AT_HWCAP);
241 if(a_val == -1)
242 {
243 puts ("querying the auxv for the hwcap failed");
244 _exit (2);
245 }
246
247 /* Indicates a 64-bit FPSCR. */
248 if (a_val & PPC_FEATURE_HAS_DFP)
249 {
250 _GET_DI_FPSCR(di_fpscr);
251
252 if (which == 0)
253 puts ("After setcontext the 64-bit FPSCR contains:");
254 else
255 puts ("After swapcontext the 64-bit FPSCR contains:");
256
257 printf("0x%.16llx\n",(unsigned long long int) di_fpscr);
258 test = (_FPSCR_TEST0_DRN | _FPSCR_TEST0_RN);
259 if((di_fpscr & (test)) != (test))
260 {
261 printf ("%s: DRN and RN bits set before getcontext were not preserved across [set|swap]context call: %m",__FUNCTION__);
262 _exit (3);
263 }
264 }
265 else
266 {
267 _GET_SI_FPSCR(di_fpscr);
268 if (which == 0)
269 puts ("After setcontext the 32-bit FPSCR contains:");
270 else
271 puts ("After swapcontext the 32-bit FPSCR contains:");
272
273 printf("0x%.8lx\n",(unsigned long int) di_fpscr);
274 test = _FPSCR_TEST0_RN;
275 if((di_fpscr & test) != test)
276 {
277 printf ("%s: RN bit set before getcontext was not preserved across [set|swap]context call: %m",__FUNCTION__);
278 _exit (4);
279 }
280 }
281 }
282
283
284 static void
285 check_called (void)
286 {
287 if (back_in_main == 0)
288 {
289 puts ("program did not reach main again");
290 _exit (5);
291 }
292 }
293
294
295 int
296 main (void)
297 {
298 atexit (check_called);
299
300 puts ("priming the FPSCR with a marker");
301 prime_special_regs (0);
302
303 puts ("making contexts");
304 if (getcontext (&ctx[0]) != 0)
305 {
306 if (errno == ENOSYS)
307 {
308 back_in_main = 1;
309 exit (0);
310 }
311
312 printf ("%s: getcontext: %m\n", __FUNCTION__);
313 exit (6);
314 }
315
316 /* Play some tricks with this context. */
317 if (++global == 1)
318 {
319 clear_special_regs ( );
320 if (setcontext (&ctx[0]) != 0)
321 {
322 printf ("%s: setcontext: %m\n", __FUNCTION__);
323 exit (7);
324 }
325 }
326 if (global != 2)
327 {
328 printf ("%s: 'global' not incremented twice\n", __FUNCTION__);
329 exit (8);
330 }
331
332 test_special_regs (0);
333
334 global = 0;
335 if (getcontext (&ctx[0]) != 0)
336 {
337 printf ("%s: getcontext: %m\n", __FUNCTION__);
338 exit (9);
339 }
340
341 if (++global == 1)
342 {
343 puts ("priming the FPSCR with a marker");
344 prime_special_regs (1);
345
346 puts ("swapping contexts");
347 if (swapcontext (&ctx[1], &ctx[0]) != 0)
348 {
349 printf ("%s: swapcontext: %m\n", __FUNCTION__);
350 exit (9);
351 }
352 }
353 if (global != 2)
354 {
355 printf ("%s: 'global' not incremented twice\n", __FUNCTION__);
356 exit (10);
357 }
358
359 test_special_regs (1);
360
361 puts ("back at main program");
362 back_in_main = 1;
363
364 puts ("test succeeded");
365 return 0;
366 }