]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/powerpc/fpu/tst-setcontext-fpscr.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / powerpc / fpu / tst-setcontext-fpscr.c
1 /* Copyright (C) 2001-2015 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 <http://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 <malloc.h>
27 #include <link.h>
28 #include <elf.h>
29 #include <sysdep.h>
30 #include <fpu_control.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 = (ElfW(auxv_t) *)malloc(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 register double fr; \
101 __asm__ ("mffs %0" : "=f" (fr)); \
102 u.d = fr; \
103 (__fpscr) = u.fpscr; \
104 u.fpscr; \
105 })
106
107 /* We make sure to zero fp after we use it in order to prevent stale data
108 in an fp register from making a test-case pass erroneously. */
109 # define _SET_DI_FPSCR(__fpscr) \
110 { union { double d; di_fpscr_t fpscr; } u; \
111 register double fr; \
112 u.fpscr = __fpscr; \
113 fr = u.d; \
114 /* Set the entire 64-bit FPSCR. */ \
115 __asm__ (".machine push; " \
116 ".machine \"power6\"; " \
117 "mtfsf 255,%0,1,0; " \
118 ".machine pop" : : "f" (fr)); \
119 fr = 0.0; \
120 }
121
122 # define _GET_SI_FPSCR(__fpscr) \
123 ({union { double d; di_fpscr_t fpscr; } u; \
124 register double fr; \
125 __asm__ ("mffs %0" : "=f" (fr)); \
126 u.d = fr; \
127 (__fpscr) = (si_fpscr_t) u.fpscr; \
128 (si_fpscr_t) u.fpscr; \
129 })
130
131 /* We make sure to zero fp after we use it in order to prevent stale data
132 in an fp register from making a test-case pass erroneously. */
133 # define _SET_SI_FPSCR(__fpscr) \
134 { union { double d; di_fpscr_t fpscr; } u; \
135 register double fr; \
136 /* More-or-less arbitrary; this is a QNaN. */ \
137 u.fpscr = 0xfff80000ULL << 32; \
138 u.fpscr |= __fpscr & 0xffffffffULL; \
139 fr = u.d; \
140 __asm__ ("mtfsf 255,%0" : : "f" (fr)); \
141 fr = 0.0; \
142 }
143
144 void prime_special_regs(int which)
145 {
146 ElfW(Addr) a_val;
147
148 di_fpscr_t di_fpscr __attribute__ ((__aligned__(8)));
149
150 a_val = query_auxv(AT_HWCAP);
151 if(a_val == -1)
152 {
153 puts ("querying the auxv for the hwcap failed");
154 _exit (1);
155 }
156
157 /* Indicates a 64-bit FPSCR. */
158 if (a_val & PPC_FEATURE_HAS_DFP)
159 {
160 _GET_DI_FPSCR(di_fpscr);
161
162 /* Overwrite the existing DRN and RN if there is one. */
163 if (which == 0)
164 di_fpscr = ((di_fpscr & _FPSCR_RESERVED) | (_FPSCR_TEST0_DRN | _FPSCR_TEST0_RN));
165 else
166 di_fpscr = ((di_fpscr & _FPSCR_RESERVED) | (_FPSCR_TEST1_DRN | _FPSCR_TEST1_RN));
167 puts ("Priming 64-bit FPSCR with:");
168 printf("0x%.16llx\n",(unsigned long long int)di_fpscr);
169
170 _SET_DI_FPSCR(di_fpscr);
171 }
172 else
173 {
174 puts ("32-bit FPSCR found and will be tested.");
175 _GET_SI_FPSCR(di_fpscr);
176
177 /* Overwrite the existing RN if there is one. */
178 if (which == 0)
179 di_fpscr = ((di_fpscr & _FPSCR_RESERVED) | (_FPSCR_TEST0_RN));
180 else
181 di_fpscr = ((di_fpscr & _FPSCR_RESERVED) | (_FPSCR_TEST1_RN));
182 puts ("Priming 32-bit FPSCR with:");
183 printf("0x%.8lx\n",(unsigned long int) di_fpscr);
184
185 _SET_SI_FPSCR(di_fpscr);
186 }
187 }
188
189 void clear_special_regs(void)
190 {
191 ElfW(Addr) a_val;
192
193 di_fpscr_t di_fpscr __attribute__ ((__aligned__(8)));
194
195 union {
196 double d;
197 unsigned long long int lli;
198 unsigned int li[2];
199 } dlli;
200
201 a_val = query_auxv(AT_HWCAP);
202 if(a_val == -1)
203 {
204 puts ("querying the auxv for the hwcap failed");
205 _exit (1);
206 }
207
208 #if __WORDSIZE == 32
209 dlli.d = ctx[0].uc_mcontext.uc_regs->fpregs.fpscr;
210 #else
211 dlli.d = ctx[0].uc_mcontext.fp_regs[32];
212 #endif
213
214 puts("The FPSCR value saved in the ucontext_t is:");
215
216 /* Indicates a 64-bit FPSCR. */
217 if (a_val & PPC_FEATURE_HAS_DFP)
218 {
219 printf("0x%.16llx\n",dlli.lli);
220 di_fpscr = 0x0;
221 puts ("Clearing the 64-bit FPSCR to:");
222 printf("0x%.16llx\n",(unsigned long long int) di_fpscr);
223
224 _SET_DI_FPSCR(di_fpscr);
225 }
226 else
227 {
228 printf("0x%.8x\n",(unsigned int) dlli.li[1]);
229 di_fpscr = 0x0;
230 puts ("Clearing the 32-bit FPSCR to:");
231 printf("0x%.8lx\n",(unsigned long int) di_fpscr);
232
233 _SET_SI_FPSCR(di_fpscr);
234 }
235 }
236
237 void test_special_regs(int which)
238 {
239 ElfW(Addr) a_val;
240 unsigned long long int test;
241
242 di_fpscr_t di_fpscr __attribute__ ((__aligned__(8)));
243
244 a_val = query_auxv(AT_HWCAP);
245 if(a_val == -1)
246 {
247 puts ("querying the auxv for the hwcap failed");
248 _exit (2);
249 }
250
251 /* Indicates a 64-bit FPSCR. */
252 if (a_val & PPC_FEATURE_HAS_DFP)
253 {
254 _GET_DI_FPSCR(di_fpscr);
255
256 if (which == 0)
257 puts ("After setcontext the 64-bit FPSCR contains:");
258 else
259 puts ("After swapcontext the 64-bit FPSCR contains:");
260
261 printf("0x%.16llx\n",(unsigned long long int) di_fpscr);
262 test = (_FPSCR_TEST0_DRN | _FPSCR_TEST0_RN);
263 if((di_fpscr & (test)) != (test))
264 {
265 printf ("%s: DRN and RN bits set before getcontext were not preserved across [set|swap]context call: %m",__FUNCTION__);
266 _exit (3);
267 }
268 }
269 else
270 {
271 _GET_SI_FPSCR(di_fpscr);
272 if (which == 0)
273 puts ("After setcontext the 32-bit FPSCR contains:");
274 else
275 puts ("After swapcontext the 32-bit FPSCR contains:");
276
277 printf("0x%.8lx\n",(unsigned long int) di_fpscr);
278 test = _FPSCR_TEST0_RN;
279 if((di_fpscr & test) != test)
280 {
281 printf ("%s: RN bit set before getcontext was not preserved across [set|swap]context call: %m",__FUNCTION__);
282 _exit (4);
283 }
284 }
285 }
286
287
288 static void
289 check_called (void)
290 {
291 if (back_in_main == 0)
292 {
293 puts ("program did not reach main again");
294 _exit (5);
295 }
296 }
297
298
299 int
300 main (void)
301 {
302 atexit (check_called);
303
304 puts ("priming the FPSCR with a marker");
305 prime_special_regs (0);
306
307 puts ("making contexts");
308 if (getcontext (&ctx[0]) != 0)
309 {
310 if (errno == ENOSYS)
311 {
312 back_in_main = 1;
313 exit (0);
314 }
315
316 printf ("%s: getcontext: %m\n", __FUNCTION__);
317 exit (6);
318 }
319
320 /* Play some tricks with this context. */
321 if (++global == 1)
322 {
323 clear_special_regs ( );
324 if (setcontext (&ctx[0]) != 0)
325 {
326 printf ("%s: setcontext: %m\n", __FUNCTION__);
327 exit (7);
328 }
329 }
330 if (global != 2)
331 {
332 printf ("%s: 'global' not incremented twice\n", __FUNCTION__);
333 exit (8);
334 }
335
336 test_special_regs (0);
337
338 global = 0;
339 if (getcontext (&ctx[0]) != 0)
340 {
341 printf ("%s: getcontext: %m\n", __FUNCTION__);
342 exit (9);
343 }
344
345 if (++global == 1)
346 {
347 puts ("priming the FPSCR with a marker");
348 prime_special_regs (1);
349
350 puts ("swapping contexts");
351 if (swapcontext (&ctx[1], &ctx[0]) != 0)
352 {
353 printf ("%s: swapcontext: %m\n", __FUNCTION__);
354 exit (9);
355 }
356 }
357 if (global != 2)
358 {
359 printf ("%s: 'global' not incremented twice\n", __FUNCTION__);
360 exit (10);
361 }
362
363 test_special_regs (1);
364
365 puts ("back at main program");
366 back_in_main = 1;
367
368 puts ("test succeeded");
369 return 0;
370 }