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