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