]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/powerpc/fpu/tst-setcontext-fpscr.c
[BZ #6411]
[thirdparty/glibc.git] / sysdeps / powerpc / fpu / tst-setcontext-fpscr.c
1 /* Copyright (C) 2001,2002,2004,2006,2007,2008 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, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
20
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ucontext.h>
26 #include <unistd.h>
27 #include <malloc.h>
28 #include <link.h>
29 #include <elf.h>
30 #include <sysdep.h>
31 #include <fpu_control.h>
32
33 static ucontext_t ctx[3];
34
35
36 volatile int global;
37
38
39 static int back_in_main;
40
41
42 volatile static ElfW(auxv_t) *auxv = NULL;
43
44 ElfW(Addr) query_auxv(int type)
45 {
46 FILE *auxv_f;
47 ElfW(auxv_t) auxv_struct;
48 ElfW(auxv_t) *auxv_temp;
49 int i = 0;
50
51 /* if the /proc/self/auxv file has not been manually copied into the heap
52 yet, then do it */
53
54 if(auxv == NULL)
55 {
56 auxv_f = fopen("/proc/self/auxv", "r");
57
58 if(auxv_f == 0)
59 {
60 perror("Error opening file for reading");
61 return 0;
62 }
63 auxv = (ElfW(auxv_t) *)malloc(getpagesize());
64
65 do
66 {
67 fread(&auxv_struct, sizeof(ElfW(auxv_t)), 1, auxv_f);
68 auxv[i] = auxv_struct;
69 i++;
70 } while(auxv_struct.a_type != AT_NULL);
71 }
72
73 auxv_temp = (ElfW(auxv_t) *)auxv;
74 i = 0;
75 do
76 {
77 if(auxv_temp[i].a_type == type)
78 {
79 return auxv_temp[i].a_un.a_val;
80 }
81 i++;
82 } while (auxv_temp[i].a_type != AT_NULL);
83
84 return 0;
85 }
86
87 typedef unsigned long long di_fpscr_t __attribute__ ((__mode__ (__DI__)));
88 typedef unsigned int si_fpscr_t __attribute__ ((__mode__ (__SI__)));
89
90 #define _FPSCR_RESERVED 0xfffffff8ffffff04ULL
91
92 #define _FPSCR_TEST0_DRN 0x0000000400000000ULL
93 #define _FPSCR_TEST0_RN 0x0000000000000003ULL
94
95 #define _FPSCR_TEST1_DRN 0x0000000300000000ULL
96 #define _FPSCR_TEST1_RN 0x0000000000000002ULL
97
98 /* Macros for accessing the hardware control word on Power6[x]. */
99 # define _GET_DI_FPSCR(__fpscr) ({ \
100 union { double d; \
101 di_fpscr_t fpscr; } \
102 tmp __attribute__ ((__aligned__(8))); \
103 __asm__ ("mffs 0; stfd%U0 0,%0" : "=m" (tmp.d) : : "fr0"); \
104 (__fpscr)=tmp.fpscr; \
105 tmp.fpscr; })
106
107 # define _SET_DI_FPSCR(__fpscr) { \
108 union { double d; di_fpscr_t fpscr; } \
109 tmp __attribute__ ((__aligned__(8))); \
110 tmp.fpscr = __fpscr; \
111 /* Set the entire 64-bit FPSCR. */ \
112 __asm__ ("lfd%U0 0,%0; mtfsf 255,0,1,0" : : "m" (tmp.d) : "fr0"); \
113 }
114
115 # define _GET_SI_FPSCR(__fpscr) ({ \
116 union { double d; \
117 si_fpscr_t cw[2]; } \
118 tmp __attribute__ ((__aligned__(8))); \
119 __asm__ ("mffs 0; stfd%U0 0,%0" : "=m" (tmp.d) : : "fr0"); \
120 (__fpscr)=tmp.cw[1]; \
121 tmp.cw[0]; })
122
123 # define _SET_SI_FPSCR(__fpscr) { \
124 union { double d; si_fpscr_t fpscr[2]; } \
125 tmp __attribute__ ((__aligned__(8))); \
126 /* More-or-less arbitrary; this is a QNaN. */ \
127 tmp.fpscr[0] = 0xFFF80000; \
128 tmp.fpscr[1] = __fpscr; \
129 __asm__ ("lfd%U0 0,%0; mtfsf 255,0" : : "m" (tmp.d) : "fr0"); \
130 }
131
132 void prime_special_regs(int which)
133 {
134 ElfW(Addr) a_val;
135
136 di_fpscr_t di_fpscr __attribute__ ((__aligned__(8)));
137
138 a_val = query_auxv(AT_HWCAP);
139 if(a_val == -1)
140 {
141 puts ("querying the auxv for the hwcap failed");
142 _exit (1);
143 }
144
145 /* Indicates a 64-bit FPSCR. */
146 if (a_val & PPC_FEATURE_HAS_DFP)
147 {
148 _GET_DI_FPSCR(di_fpscr);
149
150 /* Overwrite the existing DRN and RN if there is one. */
151 if (which == 0)
152 di_fpscr = ((di_fpscr & _FPSCR_RESERVED) | (_FPSCR_TEST0_DRN | _FPSCR_TEST0_RN));
153 else
154 di_fpscr = ((di_fpscr & _FPSCR_RESERVED) | (_FPSCR_TEST1_DRN | _FPSCR_TEST1_RN));
155 puts ("Priming 64-bit FPSCR with:");
156 printf("0x%.16llx\n",(unsigned long long int)di_fpscr);
157
158 _SET_DI_FPSCR(di_fpscr);
159 }
160 else
161 {
162 puts ("32-bit FPSCR found and will be tested.");
163 _GET_SI_FPSCR(di_fpscr);
164
165 /* Overwrite the existing RN if there is one. */
166 if (which == 0)
167 di_fpscr = ((di_fpscr & _FPSCR_RESERVED) | (_FPSCR_TEST0_RN));
168 else
169 di_fpscr = ((di_fpscr & _FPSCR_RESERVED) | (_FPSCR_TEST1_RN));
170 puts ("Priming 32-bit FPSCR with:");
171 printf("0x%.8lx\n",(unsigned long int) di_fpscr);
172
173 _SET_SI_FPSCR(di_fpscr);
174 }
175 }
176
177 void clear_special_regs(void)
178 {
179 ElfW(Addr) a_val;
180
181 di_fpscr_t di_fpscr __attribute__ ((__aligned__(8)));
182
183 union {
184 double d;
185 unsigned long long int lli;
186 unsigned int li[2];
187 } dlli;
188
189 a_val = query_auxv(AT_HWCAP);
190 if(a_val == -1)
191 {
192 puts ("querying the auxv for the hwcap failed");
193 _exit (1);
194 }
195
196 #if __WORDSIZE == 32
197 dlli.d = ctx[0].uc_mcontext.uc_regs->fpregs.fpscr;
198 #else
199 dlli.d = ctx[0].uc_mcontext.fp_regs[32];
200 #endif
201
202 puts("The FPSCR value saved in the ucontext_t is:");
203
204 /* Indicates a 64-bit FPSCR. */
205 if (a_val & PPC_FEATURE_HAS_DFP)
206 {
207 printf("0x%.16llx\n",dlli.lli);
208 di_fpscr = 0x0;
209 puts ("Clearing the 64-bit FPSCR to:");
210 printf("0x%.16llx\n",(unsigned long long int) di_fpscr);
211
212 _SET_DI_FPSCR(di_fpscr);
213 }
214 else
215 {
216 printf("0x%.8x\n",(unsigned int) dlli.li[1]);
217 di_fpscr = 0x0;
218 puts ("Clearing the 32-bit FPSCR to:");
219 printf("0x%.8lx\n",(unsigned long int) di_fpscr);
220
221 _SET_SI_FPSCR(di_fpscr);
222 }
223 }
224
225 void test_special_regs(int which)
226 {
227 ElfW(Addr) a_val;
228 unsigned long long int test;
229
230 di_fpscr_t di_fpscr __attribute__ ((__aligned__(8)));
231
232 a_val = query_auxv(AT_HWCAP);
233 if(a_val == -1)
234 {
235 puts ("querying the auxv for the hwcap failed");
236 _exit (2);
237 }
238
239 /* Indicates a 64-bit FPSCR. */
240 if (a_val & PPC_FEATURE_HAS_DFP)
241 {
242 _GET_DI_FPSCR(di_fpscr);
243
244 if (which == 0)
245 puts ("After setcontext the 64-bit FPSCR contains:");
246 else
247 puts ("After swapcontext the 64-bit FPSCR contains:");
248
249 printf("0x%.16llx\n",(unsigned long long int) di_fpscr);
250 test = (_FPSCR_TEST0_DRN | _FPSCR_TEST0_RN);
251 if((di_fpscr & (test)) != (test))
252 {
253 printf ("%s: DRN and RN bits set before getcontext were not preserved across [set|swap]context call: %m",__FUNCTION__);
254 _exit (3);
255 }
256 }
257 else
258 {
259 _GET_SI_FPSCR(di_fpscr);
260 if (which == 0)
261 puts ("After setcontext the 32-bit FPSCR contains:");
262 else
263 puts ("After swapcontext the 32-bit FPSCR contains:");
264
265 printf("0x%.8lx\n",(unsigned long int) di_fpscr);
266 test = _FPSCR_TEST0_RN;
267 if((di_fpscr & test) != test)
268 {
269 printf ("%s: RN bit set before getcontext was not preserved across [set|swap]context call: %m",__FUNCTION__);
270 _exit (4);
271 }
272 }
273 }
274
275
276 static void
277 check_called (void)
278 {
279 if (back_in_main == 0)
280 {
281 puts ("program did not reach main again");
282 _exit (5);
283 }
284 }
285
286
287 int
288 main (void)
289 {
290 atexit (check_called);
291
292 puts ("priming the FPSCR with a marker");
293 prime_special_regs (0);
294
295 puts ("making contexts");
296 if (getcontext (&ctx[0]) != 0)
297 {
298 if (errno == ENOSYS)
299 {
300 back_in_main = 1;
301 exit (0);
302 }
303
304 printf ("%s: getcontext: %m\n", __FUNCTION__);
305 exit (6);
306 }
307
308 /* Play some tricks with this context. */
309 if (++global == 1)
310 {
311 clear_special_regs ( );
312 if (setcontext (&ctx[0]) != 0)
313 {
314 printf ("%s: setcontext: %m\n", __FUNCTION__);
315 exit (7);
316 }
317 }
318 if (global != 2)
319 {
320 printf ("%s: 'global' not incremented twice\n", __FUNCTION__);
321 exit (8);
322 }
323
324 test_special_regs (0);
325
326 global = 0;
327 if (getcontext (&ctx[0]) != 0)
328 {
329 printf ("%s: getcontext: %m\n", __FUNCTION__);
330 exit (9);
331 }
332
333 if (++global == 1)
334 {
335 puts ("priming the FPSCR with a marker");
336 prime_special_regs (1);
337
338 puts ("swapping contexts");
339 if (swapcontext (&ctx[1], &ctx[0]) != 0)
340 {
341 printf ("%s: swapcontext: %m\n", __FUNCTION__);
342 exit (9);
343 }
344 }
345 if (global != 2)
346 {
347 printf ("%s: 'global' not incremented twice\n", __FUNCTION__);
348 exit (10);
349 }
350
351 test_special_regs (1);
352
353 puts ("back at main program");
354 back_in_main = 1;
355
356 puts ("test succeeded");
357 return 0;
358 }