5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24 */
25 /*
26 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29
30 #undef lint
31 #include <signal.h>
32 #include <siginfo.h>
33 #include <ucontext.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <thread.h>
38 #include <math.h>
39 #if defined(__SUNPRO_C)
40 #include <sunmath.h>
41 #endif
42 #include <fenv.h>
43 #include "fex_handler.h"
44 #include "fenv_inlines.h"
45
46 #if defined(__sparc) && !defined(__sparcv9)
47 #include <sys/procfs.h>
48 #endif
49
50 /* 2.x signal.h doesn't declare sigemptyset or sigismember
51 if they're #defined (see sys/signal.h) */
52 extern int sigemptyset(sigset_t *);
53 extern int sigismember(const sigset_t *, int);
54
55 /* external globals */
56 void (*__mt_fex_sync)() = NULL; /* for synchronization with libmtsk */
57 #pragma weak __mt_fex_sync
58
59 void (*__libm_mt_fex_sync)() = NULL; /* new, improved version of above */
60 #pragma weak __libm_mt_fex_sync
61
62 /* private variables */
63 static fex_handler_t main_handlers;
64 static int handlers_initialized = 0;
65 static thread_key_t handlers_key;
66 static mutex_t handlers_key_lock = DEFAULTMUTEX;
67
68 static struct sigaction oact = { 0, SIG_DFL };
69 static mutex_t hdlr_lock = DEFAULTMUTEX;
70 static int hdlr_installed = 0;
71
72 /* private const data */
73 static const int te_bit[FEX_NUM_EXC] = {
74 1 << fp_trap_inexact,
75 1 << fp_trap_division,
76 1 << fp_trap_underflow,
77 1 << fp_trap_overflow,
78 1 << fp_trap_invalid,
79 1 << fp_trap_invalid,
80 1 << fp_trap_invalid,
81 1 << fp_trap_invalid,
82 1 << fp_trap_invalid,
83 1 << fp_trap_invalid,
84 1 << fp_trap_invalid,
85 1 << fp_trap_invalid
86 };
87
88 /*
89 * Return the traps to be enabled given the current handling modes
90 * and flags
91 */
92 static int
93 __fex_te_needed(struct fex_handler_data *thr_handlers, unsigned long fsr)
94 {
95 int i, ex, te;
96
97 /* set traps for handling modes */
98 te = 0;
99 for (i = 0; i < FEX_NUM_EXC; i++)
100 if (thr_handlers[i].__mode != FEX_NONSTOP)
101 te |= te_bit[i];
102
103 /* add traps for retrospective diagnostics */
104 if (fex_get_log()) {
105 ex = (int)__fenv_get_ex(fsr);
106 if (!(ex & FE_INEXACT))
107 te |= (1 << fp_trap_inexact);
108 if (!(ex & FE_UNDERFLOW))
109 te |= (1 << fp_trap_underflow);
110 if (!(ex & FE_OVERFLOW))
111 te |= (1 << fp_trap_overflow);
112 if (!(ex & FE_DIVBYZERO))
113 te |= (1 << fp_trap_division);
114 if (!(ex & FE_INVALID))
115 te |= (1 << fp_trap_invalid);
116 }
117
118 return te;
119 }
120
121 /*
122 * The following function synchronizes with libmtsk (SPARC only, for now)
123 */
124 static void
125 __fex_sync_with_libmtsk(int begin, int master)
126 {
127 static fenv_t master_env;
128 static int env_initialized = 0;
129 static mutex_t env_lock = DEFAULTMUTEX;
130
131 if (begin) {
132 mutex_lock(&env_lock);
133 if (master) {
134 (void) fegetenv(&master_env);
135 env_initialized = 1;
136 }
137 else if (env_initialized)
138 (void) fesetenv(&master_env);
139 mutex_unlock(&env_lock);
140 }
141 else if (master && fex_get_log())
142 __fex_update_te();
143 }
144
145 /*
146 * The following function may be used for synchronization with any
147 * internal project that manages multiple threads
148 */
149 enum __libm_mt_fex_sync_actions {
150 __libm_mt_fex_start_master = 0,
151 __libm_mt_fex_start_slave,
152 __libm_mt_fex_finish_master,
153 __libm_mt_fex_finish_slave
154 };
155
156 struct __libm_mt_fex_sync_data {
157 fenv_t master_env;
158 int initialized;
159 mutex_t lock;
160 };
161
162 static void
163 __fex_sync_with_threads(enum __libm_mt_fex_sync_actions action,
164 struct __libm_mt_fex_sync_data *thr_env)
165 {
166 switch (action) {
167 case __libm_mt_fex_start_master:
168 mutex_lock(&thr_env->lock);
169 (void) fegetenv(&thr_env->master_env);
170 thr_env->initialized = 1;
171 mutex_unlock(&thr_env->lock);
172 break;
173
174 case __libm_mt_fex_start_slave:
175 mutex_lock(&thr_env->lock);
176 if (thr_env->initialized)
177 (void) fesetenv(&thr_env->master_env);
178 mutex_unlock(&thr_env->lock);
179 break;
180
181 case __libm_mt_fex_finish_master:
182 #if defined(__x86)
183 __fex_update_te();
184 #else
185 if (fex_get_log())
186 __fex_update_te();
187 #endif
188 break;
189
190 case __libm_mt_fex_finish_slave:
191 #if defined(__x86)
192 /* clear traps, making all accrued flags visible in status word */
193 {
194 unsigned long fsr;
195 __fenv_getfsr(&fsr);
196 __fenv_set_te(fsr, 0);
197 __fenv_setfsr(&fsr);
198 }
199 #endif
200 break;
201 }
202 }
203
204 #if defined(__sparc)
205
206 /*
207 * Code for setting or clearing interval mode on US-III and above.
208 * This is embedded as data so we don't have to mark the library
209 * as a v8plusb/v9b object. (I could have just used one entry and
210 * modified the second word to set the bits I want, but that would
211 * have required another mutex.)
212 */
213 static const unsigned int siam[][2] = {
214 { 0x81c3e008, 0x81b01020 }, /* retl, siam 0 */
215 { 0x81c3e008, 0x81b01024 }, /* retl, siam 4 */
216 { 0x81c3e008, 0x81b01025 }, /* retl, siam 5 */
217 { 0x81c3e008, 0x81b01026 }, /* retl, siam 6 */
218 { 0x81c3e008, 0x81b01027 } /* retl, siam 7 */
219 };
220
221 /*
222 * If a handling mode is in effect, apply it; otherwise invoke the
223 * saved handler
224 */
225 static void
226 __fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap)
227 {
228 struct fex_handler_data *thr_handlers;
229 struct sigaction act;
230 void (*handler)(), (*siamp)();
231 int mode, i;
232 enum fex_exception e;
233 fex_info_t info;
234 unsigned long fsr, tmpfsr, addr;
235 unsigned int gsr;
236
237 /* determine which exception occurred */
238 switch (sip->si_code) {
239 case FPE_FLTDIV:
240 e = fex_division;
241 break;
242 case FPE_FLTOVF:
243 e = fex_overflow;
244 break;
245 case FPE_FLTUND:
246 e = fex_underflow;
247 break;
248 case FPE_FLTRES:
249 e = fex_inexact;
250 break;
251 case FPE_FLTINV:
252 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0)
253 goto not_ieee;
254 break;
255 default:
256 /* not an IEEE exception */
257 goto not_ieee;
258 }
259
260 /* get the handling mode */
261 mode = FEX_NOHANDLER;
262 handler = oact.sa_handler; /* for log; just looking, no need to lock */
263 thr_handlers = __fex_get_thr_handlers();
264 if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) {
265 mode = thr_handlers[(int)e].__mode;
266 handler = thr_handlers[(int)e].__handler;
267 }
268
269 /* make an entry in the log of retro. diag. if need be */
270 i = ((int)uap->uc_mcontext.fpregs.fpu_fsr >> 5) & 0x1f;
271 __fex_mklog(uap, (char *)sip->si_addr, i, e, mode, (void *)handler);
272
273 /* handle the exception based on the mode */
274 if (mode == FEX_NOHANDLER)
275 goto not_ieee;
276 else if (mode == FEX_ABORT)
277 abort();
278 else if (mode == FEX_SIGNAL) {
279 handler(sig, sip, uap);
280 return;
281 }
282
283 /* custom or nonstop mode; disable traps and clear flags */
284 __fenv_getfsr(&fsr);
285 __fenv_set_te(fsr, 0);
286 __fenv_set_ex(fsr, 0);
287
288 /* if interval mode was set, clear it, then substitute the
289 interval rounding direction and clear ns mode in the fsr */
290 #ifdef __sparcv9
291 gsr = uap->uc_mcontext.asrs[3];
292 #else
293 gsr = 0;
294 if (uap->uc_mcontext.xrs.xrs_id == XRS_ID)
295 gsr = (*(unsigned long long*)((prxregset_t*)uap->uc_mcontext.
296 xrs.xrs_ptr)->pr_un.pr_v8p.pr_filler);
297 #endif
298 gsr = (gsr >> 25) & 7;
299 if (gsr & 4) {
300 siamp = (void (*)()) siam[0];
301 siamp();
302 tmpfsr = fsr;
303 fsr = (fsr & ~0xc0400000ul) | ((gsr & 3) << 30);
304 }
305 __fenv_setfsr(&fsr);
306
307 /* decode the operation */
308 __fex_get_op(sip, uap, &info);
309
310 /* if a custom mode handler is installed, invoke it */
311 if (mode == FEX_CUSTOM) {
312 /* if we got here from feraiseexcept, pass dummy info */
313 addr = (unsigned long)sip->si_addr;
314 if (addr >= (unsigned long)feraiseexcept &&
315 addr < (unsigned long)fetestexcept) {
316 info.op = fex_other;
317 info.op1.type = info.op2.type = info.res.type =
318 fex_nodata;
319 }
320
321 /* restore interval mode if it was set, and put the original
322 rounding direction and ns mode back in the fsr */
323 if (gsr & 4) {
324 __fenv_setfsr(&tmpfsr);
325 siamp = (void (*)()) siam[1 + (gsr & 3)];
326 siamp();
327 }
328
329 handler(1 << (int)e, &info);
330
331 /* restore modes in case the user's handler changed them */
332 if (gsr & 4) {
333 siamp = (void (*)()) siam[0];
334 siamp();
335 }
336 __fenv_setfsr(&fsr);
337 }
338
339 /* stuff the result */
340 __fex_st_result(sip, uap, &info);
341
342 /* "or" in any exception flags and update traps */
343 fsr = uap->uc_mcontext.fpregs.fpu_fsr;
344 fsr |= ((info.flags & 0x1f) << 5);
345 i = __fex_te_needed(thr_handlers, fsr);
346 __fenv_set_te(fsr, i);
347 uap->uc_mcontext.fpregs.fpu_fsr = fsr;
348 return;
349
350 not_ieee:
351 /* revert to the saved handler (if any) */
352 mutex_lock(&hdlr_lock);
353 act = oact;
354 mutex_unlock(&hdlr_lock);
355 switch ((unsigned long)act.sa_handler) {
356 case (unsigned long)SIG_DFL:
357 /* simulate trap with no handler installed */
358 sigaction(SIGFPE, &act, NULL);
359 kill(getpid(), SIGFPE);
360 break;
361 #if !defined(__lint)
362 case (unsigned long)SIG_IGN:
363 break;
364 #endif
365 default:
366 act.sa_handler(sig, sip, uap);
367 }
368 }
369
370 #elif defined(__x86)
371
372 #if defined(__amd64)
373 #define test_sse_hw 1
374 #else
375 extern int _sse_hw;
376 #define test_sse_hw _sse_hw
377 #endif
378
379 #if !defined(REG_PC)
380 #define REG_PC EIP
381 #endif
382
383 /*
384 * If a handling mode is in effect, apply it; otherwise invoke the
385 * saved handler
386 */
387 static void
388 __fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap)
389 {
390 struct fex_handler_data *thr_handlers;
391 struct sigaction act;
392 void (*handler)() = NULL, (*simd_handler[4])();
393 int mode, simd_mode[4], i, len, accrued, *ap;
394 unsigned int cwsw, oldcwsw, mxcsr, oldmxcsr;
395 enum fex_exception e, simd_e[4];
396 fex_info_t info, simd_info[4];
397 unsigned long addr;
398 siginfo_t osip = *sip;
399 sseinst_t inst;
400
401 /* check for an exception caused by an SSE instruction */
402 if (!(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status & 0x80)) {
403 len = __fex_parse_sse(uap, &inst);
404 if (len == 0)
405 goto not_ieee;
406
407 /* disable all traps and clear flags */
408 __fenv_getcwsw(&oldcwsw);
409 cwsw = (oldcwsw & ~0x3f) | 0x003f0000;
410 __fenv_setcwsw(&cwsw);
411 __fenv_getmxcsr(&oldmxcsr);
412 mxcsr = (oldmxcsr & ~0x3f) | 0x1f80;
413 __fenv_setmxcsr(&mxcsr);
414
415 if ((int)inst.op & SIMD) {
416 __fex_get_simd_op(uap, &inst, simd_e, simd_info);
417
418 thr_handlers = __fex_get_thr_handlers();
419 addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC];
420 accrued = uap->uc_mcontext.fpregs.fp_reg_set.
421 fpchip_state.mxcsr;
422
423 e = (enum fex_exception)-1;
424 mode = FEX_NONSTOP;
425 for (i = 0; i < 4; i++) {
426 if ((int)simd_e[i] < 0)
427 continue;
428
429 e = simd_e[i];
430 simd_mode[i] = FEX_NOHANDLER;
431 simd_handler[i] = oact.sa_handler;
432 if (thr_handlers &&
433 thr_handlers[(int)e].__mode !=
434 FEX_NOHANDLER) {
435 simd_mode[i] =
436 thr_handlers[(int)e].__mode;
437 simd_handler[i] =
438 thr_handlers[(int)e].__handler;
439 }
440 accrued &= ~te_bit[(int)e];
441 switch (simd_mode[i]) {
442 case FEX_ABORT:
443 mode = FEX_ABORT;
444 break;
445 case FEX_SIGNAL:
446 if (mode != FEX_ABORT)
447 mode = FEX_SIGNAL;
448 handler = simd_handler[i];
449 break;
450 case FEX_NOHANDLER:
451 if (mode != FEX_ABORT && mode !=
452 FEX_SIGNAL)
453 mode = FEX_NOHANDLER;
454 break;
455 }
456 }
457 if (e == (enum fex_exception)-1) {
458 __fenv_setcwsw(&oldcwsw);
459 __fenv_setmxcsr(&oldmxcsr);
460 goto not_ieee;
461 }
462 accrued |= uap->uc_mcontext.fpregs.fp_reg_set.
463 fpchip_state.status;
464 ap = __fex_accrued();
465 accrued |= *ap;
466 accrued &= 0x3d;
467
468 for (i = 0; i < 4; i++) {
469 if ((int)simd_e[i] < 0)
470 continue;
471
472 __fex_mklog(uap, (char *)addr, accrued,
473 simd_e[i], simd_mode[i],
474 (void *)simd_handler[i]);
475 }
476
477 if (mode == FEX_NOHANDLER) {
478 __fenv_setcwsw(&oldcwsw);
479 __fenv_setmxcsr(&oldmxcsr);
480 goto not_ieee;
481 } else if (mode == FEX_ABORT) {
482 abort();
483 } else if (mode == FEX_SIGNAL) {
484 __fenv_setcwsw(&oldcwsw);
485 __fenv_setmxcsr(&oldmxcsr);
486 handler(sig, &osip, uap);
487 return;
488 }
489
490 *ap = 0;
491 for (i = 0; i < 4; i++) {
492 if ((int)simd_e[i] < 0)
493 continue;
494
495 if (simd_mode[i] == FEX_CUSTOM) {
496 handler(1 << (int)simd_e[i],
497 &simd_info[i]);
498 __fenv_setcwsw(&cwsw);
499 __fenv_setmxcsr(&mxcsr);
500 }
501 }
502
503 __fex_st_simd_result(uap, &inst, simd_e, simd_info);
504 for (i = 0; i < 4; i++) {
505 if ((int)simd_e[i] < 0)
506 continue;
507
508 accrued |= simd_info[i].flags;
509 }
510
511 if ((int)inst.op & INTREG) {
512 /* set MMX mode */
513 #if defined(__amd64)
514 uap->uc_mcontext.fpregs.fp_reg_set.
515 fpchip_state.sw &= ~0x3800;
516 uap->uc_mcontext.fpregs.fp_reg_set.
517 fpchip_state.fctw = 0;
518 #else
519 uap->uc_mcontext.fpregs.fp_reg_set.
520 fpchip_state.state[1] &= ~0x3800;
521 uap->uc_mcontext.fpregs.fp_reg_set.
522 fpchip_state.state[2] = 0;
523 #endif
524 }
525 } else {
526 e = __fex_get_sse_op(uap, &inst, &info);
527 if ((int)e < 0) {
528 __fenv_setcwsw(&oldcwsw);
529 __fenv_setmxcsr(&oldmxcsr);
530 goto not_ieee;
531 }
532
533 mode = FEX_NOHANDLER;
534 handler = oact.sa_handler;
535 thr_handlers = __fex_get_thr_handlers();
536 if (thr_handlers && thr_handlers[(int)e].__mode !=
537 FEX_NOHANDLER) {
538 mode = thr_handlers[(int)e].__mode;
539 handler = thr_handlers[(int)e].__handler;
540 }
541
542 addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC];
543 accrued = uap->uc_mcontext.fpregs.fp_reg_set.
544 fpchip_state.mxcsr & ~te_bit[(int)e];
545 accrued |= uap->uc_mcontext.fpregs.fp_reg_set.
546 fpchip_state.status;
547 ap = __fex_accrued();
548 accrued |= *ap;
549 accrued &= 0x3d;
550 __fex_mklog(uap, (char *)addr, accrued, e, mode,
551 (void *)handler);
552
553 if (mode == FEX_NOHANDLER) {
554 __fenv_setcwsw(&oldcwsw);
555 __fenv_setmxcsr(&oldmxcsr);
556 goto not_ieee;
557 } else if (mode == FEX_ABORT) {
558 abort();
559 } else if (mode == FEX_SIGNAL) {
560 __fenv_setcwsw(&oldcwsw);
561 __fenv_setmxcsr(&oldmxcsr);
562 handler(sig, &osip, uap);
563 return;
564 } else if (mode == FEX_CUSTOM) {
565 *ap = 0;
566 if (addr >= (unsigned long)feraiseexcept &&
567 addr < (unsigned long)fetestexcept) {
568 info.op = fex_other;
569 info.op1.type = info.op2.type =
570 info.res.type = fex_nodata;
571 }
572 handler(1 << (int)e, &info);
573 __fenv_setcwsw(&cwsw);
574 __fenv_setmxcsr(&mxcsr);
575 }
576
577 __fex_st_sse_result(uap, &inst, e, &info);
578 accrued |= info.flags;
579
580 #if defined(__amd64)
581 /*
582 * In 64-bit mode, the 32-bit convert-to-integer
583 * instructions zero the upper 32 bits of the
584 * destination. (We do this here and not in
585 * __fex_st_sse_result because __fex_st_sse_result
586 * can be called from __fex_st_simd_result, too.)
587 */
588 if (inst.op == cvtss2si || inst.op == cvttss2si ||
589 inst.op == cvtsd2si || inst.op == cvttsd2si)
590 inst.op1->i[1] = 0;
591 #endif
592 }
593
594 /* advance the pc past the SSE instruction */
595 uap->uc_mcontext.gregs[REG_PC] += len;
596 goto update_state;
597 }
598
599 /* determine which exception occurred */
600 __fex_get_x86_exc(sip, uap);
601 switch (sip->si_code) {
602 case FPE_FLTDIV:
603 e = fex_division;
604 break;
605 case FPE_FLTOVF:
606 e = fex_overflow;
607 break;
608 case FPE_FLTUND:
609 e = fex_underflow;
610 break;
611 case FPE_FLTRES:
612 e = fex_inexact;
613 break;
614 case FPE_FLTINV:
615 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0)
616 goto not_ieee;
617 break;
618 default:
619 /* not an IEEE exception */
620 goto not_ieee;
621 }
622
623 /* get the handling mode */
624 mode = FEX_NOHANDLER;
625 handler = oact.sa_handler; /* for log; just looking, no need to lock */
626 thr_handlers = __fex_get_thr_handlers();
627 if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) {
628 mode = thr_handlers[(int)e].__mode;
629 handler = thr_handlers[(int)e].__handler;
630 }
631
632 /* make an entry in the log of retro. diag. if need be */
633 #if defined(__amd64)
634 addr = (unsigned long)uap->uc_mcontext.fpregs.fp_reg_set.
635 fpchip_state.rip;
636 #else
637 addr = (unsigned long)uap->uc_mcontext.fpregs.fp_reg_set.
638 fpchip_state.state[3];
639 #endif
640 accrued = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status &
641 ~te_bit[(int)e];
642 if (test_sse_hw)
643 accrued |= uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
644 mxcsr;
645 ap = __fex_accrued();
646 accrued |= *ap;
647 accrued &= 0x3d;
648 __fex_mklog(uap, (char *)addr, accrued, e, mode, (void *)handler);
649
650 /* handle the exception based on the mode */
651 if (mode == FEX_NOHANDLER)
652 goto not_ieee;
653 else if (mode == FEX_ABORT)
654 abort();
655 else if (mode == FEX_SIGNAL) {
656 handler(sig, &osip, uap);
657 return;
658 }
659
660 /* disable all traps and clear flags */
661 __fenv_getcwsw(&cwsw);
662 cwsw = (cwsw & ~0x3f) | 0x003f0000;
663 __fenv_setcwsw(&cwsw);
664 if (test_sse_hw) {
665 __fenv_getmxcsr(&mxcsr);
666 mxcsr = (mxcsr & ~0x3f) | 0x1f80;
667 __fenv_setmxcsr(&mxcsr);
668 }
669 *ap = 0;
670
671 /* decode the operation */
672 __fex_get_op(sip, uap, &info);
673
674 /* if a custom mode handler is installed, invoke it */
675 if (mode == FEX_CUSTOM) {
676 /* if we got here from feraiseexcept, pass dummy info */
677 if (addr >= (unsigned long)feraiseexcept &&
678 addr < (unsigned long)fetestexcept) {
679 info.op = fex_other;
680 info.op1.type = info.op2.type = info.res.type =
681 fex_nodata;
682 }
683
684 handler(1 << (int)e, &info);
685
686 /* restore modes in case the user's handler changed them */
687 __fenv_setcwsw(&cwsw);
688 if (test_sse_hw)
689 __fenv_setmxcsr(&mxcsr);
690 }
691
692 /* stuff the result */
693 __fex_st_result(sip, uap, &info);
694 accrued |= info.flags;
695
696 update_state:
697 accrued &= 0x3d;
698 i = __fex_te_needed(thr_handlers, accrued);
699 *ap = accrued & i;
700 #if defined(__amd64)
701 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw &= ~0x3d;
702 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= (accrued & ~i);
703 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw |= 0x3d;
704 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw &= ~i;
705 #else
706 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] &= ~0x3d;
707 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] |=
708 (accrued & ~i);
709 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] |= 0x3d;
710 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] &= ~i;
711 #endif
712 if (test_sse_hw) {
713 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &= ~0x3d;
714 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr |=
715 0x1e80 | (accrued & ~i);
716 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &=
717 ~(i << 7);
718 }
719 return;
720
721 not_ieee:
722 /* revert to the saved handler (if any) */
723 mutex_lock(&hdlr_lock);
724 act = oact;
725 mutex_unlock(&hdlr_lock);
726 switch ((unsigned long)act.sa_handler) {
727 case (unsigned long)SIG_DFL:
728 /* simulate trap with no handler installed */
729 sigaction(SIGFPE, &act, NULL);
730 kill(getpid(), SIGFPE);
731 break;
732 #if !defined(__lint)
733 case (unsigned long)SIG_IGN:
734 break;
735 #endif
736 default:
737 act.sa_handler(sig, &osip, uap);
738 }
739 }
740
741 #else
742 #error Unknown architecture
743 #endif
744
745 /*
746 * Return a pointer to the thread-specific handler data, and
747 * initialize it if necessary
748 */
749 struct fex_handler_data *
750 __fex_get_thr_handlers()
751 {
752 struct fex_handler_data *ptr;
753 unsigned long fsr;
754 int i, te;
755
756 if (thr_main()) {
757 if (!handlers_initialized) {
758 /* initialize to FEX_NOHANDLER if trap is enabled,
759 FEX_NONSTOP if trap is disabled */
760 __fenv_getfsr(&fsr);
761 te = (int)__fenv_get_te(fsr);
762 for (i = 0; i < FEX_NUM_EXC; i++)
763 main_handlers[i].__mode =
764 ((te & te_bit[i])? FEX_NOHANDLER : FEX_NONSTOP);
765 handlers_initialized = 1;
766 }
767 return main_handlers;
768 }
769 else {
770 ptr = NULL;
771 mutex_lock(&handlers_key_lock);
772 if (thr_getspecific(handlers_key, (void **)&ptr) != 0 &&
773 thr_keycreate(&handlers_key, free) != 0) {
774 mutex_unlock(&handlers_key_lock);
775 return NULL;
776 }
777 mutex_unlock(&handlers_key_lock);
778 if (!ptr) {
779 if ((ptr = (struct fex_handler_data *)
780 malloc(sizeof(fex_handler_t))) == NULL) {
781 return NULL;
782 }
783 if (thr_setspecific(handlers_key, (void *)ptr) != 0) {
784 (void)free(ptr);
785 return NULL;
786 }
787 /* initialize to FEX_NOHANDLER if trap is enabled,
788 FEX_NONSTOP if trap is disabled */
789 __fenv_getfsr(&fsr);
790 te = (int)__fenv_get_te(fsr);
791 for (i = 0; i < FEX_NUM_EXC; i++)
792 ptr[i].__mode = ((te & te_bit[i])? FEX_NOHANDLER : FEX_NONSTOP);
793 }
794 return ptr;
795 }
796 }
797
798 /*
799 * Update the trap enable bits according to the selected modes
800 */
801 void
802 __fex_update_te()
803 {
804 struct fex_handler_data *thr_handlers;
805 struct sigaction act, tmpact;
806 sigset_t blocked;
807 unsigned long fsr;
808 int te;
809
810 /* determine which traps are needed */
811 thr_handlers = __fex_get_thr_handlers();
812 __fenv_getfsr(&fsr);
813 te = __fex_te_needed(thr_handlers, fsr);
814
815 /* install __fex_hdlr as necessary */
816 if (!hdlr_installed && te) {
817 act.sa_handler = __fex_hdlr;
818 sigemptyset(&act.sa_mask);
819 act.sa_flags = SA_SIGINFO;
820 sigaction(SIGFPE, &act, &tmpact);
821 if (tmpact.sa_handler != __fex_hdlr)
822 {
823 mutex_lock(&hdlr_lock);
824 oact = tmpact;
825 mutex_unlock(&hdlr_lock);
826 }
827 hdlr_installed = 1;
828 }
829
830 /* set the new trap enable bits (only if SIGFPE is not blocked) */
831 if (sigprocmask(0, NULL, &blocked) == 0 &&
832 !sigismember(&blocked, SIGFPE)) {
833 __fenv_set_te(fsr, te);
834 __fenv_setfsr(&fsr);
835 }
836
837 /* synchronize with libmtsk */
838 __mt_fex_sync = __fex_sync_with_libmtsk;
839
840 /* synchronize with other projects */
841 __libm_mt_fex_sync = __fex_sync_with_threads;
842 }
|
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 /*
27 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 #undef lint
32 #include <signal.h>
33 #include <siginfo.h>
34 #include <ucontext.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <thread.h>
39 #include <math.h>
40 #if defined(__SUNPRO_C)
41 #include <sunmath.h>
42 #endif
43 #include <fenv.h>
44 #include "fex_handler.h"
45 #include "fenv_inlines.h"
46
47 #if defined(__sparc) && !defined(__sparcv9)
48 #include <sys/procfs.h>
49 #endif
50
51 /*
52 * 2.x signal.h doesn't declare sigemptyset or sigismember
53 * if they're #define'd (see sys/signal.h)
54 */
55 extern int sigemptyset(sigset_t *);
56 extern int sigismember(const sigset_t *, int);
57
58 /* external globals */
59 void (*__mt_fex_sync)() = NULL; /* for synchronization with libmtsk */
60 #pragma weak __mt_fex_sync
61
62 void (*__libm_mt_fex_sync)() = NULL; /* new, improved version of above */
63 #pragma weak __libm_mt_fex_sync
64
65 /* private variables */
66 static fex_handler_t main_handlers;
67 static int handlers_initialized = 0;
68 static thread_key_t handlers_key;
69 static mutex_t handlers_key_lock = DEFAULTMUTEX;
70 static struct sigaction oact = { 0, SIG_DFL };
71 static mutex_t hdlr_lock = DEFAULTMUTEX;
72 static int hdlr_installed = 0;
73
74 /* private const data */
75 static const int te_bit[FEX_NUM_EXC] = {
76 1 << fp_trap_inexact, 1 << fp_trap_division, 1 << fp_trap_underflow,
77 1 << fp_trap_overflow, 1 << fp_trap_invalid, 1 << fp_trap_invalid,
78 1 << fp_trap_invalid, 1 << fp_trap_invalid, 1 << fp_trap_invalid,
79 1 << fp_trap_invalid, 1 << fp_trap_invalid, 1 << fp_trap_invalid
80 };
81
82 /*
83 * Return the traps to be enabled given the current handling modes
84 * and flags
85 */
86 static int
87 __fex_te_needed(struct fex_handler_data *thr_handlers, unsigned long fsr)
88 {
89 int i, ex, te;
90
91 /* set traps for handling modes */
92 te = 0;
93
94 for (i = 0; i < FEX_NUM_EXC; i++)
95 if (thr_handlers[i].__mode != FEX_NONSTOP)
96 te |= te_bit[i];
97
98 /* add traps for retrospective diagnostics */
99
100 if (fex_get_log()) {
101 ex = (int)__fenv_get_ex(fsr);
102
103 if (!(ex & FE_INEXACT))
104 te |= (1 << fp_trap_inexact);
105
106 if (!(ex & FE_UNDERFLOW))
107 te |= (1 << fp_trap_underflow);
108
109 if (!(ex & FE_OVERFLOW))
110 te |= (1 << fp_trap_overflow);
111
112 if (!(ex & FE_DIVBYZERO))
113 te |= (1 << fp_trap_division);
114
115 if (!(ex & FE_INVALID))
116 te |= (1 << fp_trap_invalid);
117 }
118
119 return (te);
120 }
121
122 /*
123 * The following function synchronizes with libmtsk (SPARC only, for now)
124 */
125 static void
126 __fex_sync_with_libmtsk(int begin, int master)
127 {
128 static fenv_t master_env;
129 static int env_initialized = 0;
130 static mutex_t env_lock = DEFAULTMUTEX;
131
132 if (begin) {
133 mutex_lock(&env_lock);
134
135 if (master) {
136 (void) fegetenv(&master_env);
137 env_initialized = 1;
138 } else if (env_initialized) {
139 (void) fesetenv(&master_env);
140 }
141
142 mutex_unlock(&env_lock);
143 } else if (master && fex_get_log()) {
144 __fex_update_te();
145 }
146 }
147
148 /*
149 * The following function may be used for synchronization with any
150 * internal project that manages multiple threads
151 */
152 enum __libm_mt_fex_sync_actions {
153 __libm_mt_fex_start_master = 0, __libm_mt_fex_start_slave,
154 __libm_mt_fex_finish_master, __libm_mt_fex_finish_slave
155 };
156
157 struct __libm_mt_fex_sync_data {
158 fenv_t master_env;
159 int initialized;
160 mutex_t lock;
161 };
162
163 static void
164 __fex_sync_with_threads(enum __libm_mt_fex_sync_actions action, struct
165 __libm_mt_fex_sync_data *thr_env)
166 {
167 switch (action) {
168 case __libm_mt_fex_start_master:
169 mutex_lock(&thr_env->lock);
170 (void) fegetenv(&thr_env->master_env);
171 thr_env->initialized = 1;
172 mutex_unlock(&thr_env->lock);
173 break;
174
175 case __libm_mt_fex_start_slave:
176 mutex_lock(&thr_env->lock);
177
178 if (thr_env->initialized)
179 (void) fesetenv(&thr_env->master_env);
180
181 mutex_unlock(&thr_env->lock);
182 break;
183
184 case __libm_mt_fex_finish_master:
185 #if defined(__x86)
186 __fex_update_te();
187 #else
188 if (fex_get_log())
189 __fex_update_te();
190 #endif
191 break;
192
193 case __libm_mt_fex_finish_slave:
194 #if defined(__x86)
195 /*
196 * clear traps, making all accrued flags visible in status
197 * word
198 */
199 {
200 unsigned long fsr;
201
202 __fenv_getfsr(&fsr);
203 __fenv_set_te(fsr, 0);
204 __fenv_setfsr(&fsr);
205 }
206 #endif
207 break;
208 }
209 }
210
211 #if defined(__sparc)
212 /*
213 * Code for setting or clearing interval mode on US-III and above.
214 * This is embedded as data so we don't have to mark the library
215 * as a v8plusb/v9b object. (I could have just used one entry and
216 * modified the second word to set the bits I want, but that would
217 * have required another mutex.)
218 */
219 static const unsigned int siam[][2] = {
220 { 0x81c3e008, 0x81b01020 }, /* retl, siam 0 */
221 { 0x81c3e008, 0x81b01024 }, /* retl, siam 4 */
222 { 0x81c3e008, 0x81b01025 }, /* retl, siam 5 */
223 { 0x81c3e008, 0x81b01026 }, /* retl, siam 6 */
224 { 0x81c3e008, 0x81b01027 } /* retl, siam 7 */
225 };
226
227 /*
228 * If a handling mode is in effect, apply it; otherwise invoke the
229 * saved handler
230 */
231 static void
232 __fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap)
233 {
234 struct fex_handler_data *thr_handlers;
235 struct sigaction act;
236
237 void (*handler)(), (*siamp)();
238
239 int mode, i;
240 enum fex_exception e;
241 fex_info_t info;
242 unsigned long fsr, tmpfsr, addr;
243 unsigned int gsr;
244
245 /* determine which exception occurred */
246 switch (sip->si_code) {
247 case FPE_FLTDIV:
248 e = fex_division;
249 break;
250 case FPE_FLTOVF:
251 e = fex_overflow;
252 break;
253 case FPE_FLTUND:
254 e = fex_underflow;
255 break;
256 case FPE_FLTRES:
257 e = fex_inexact;
258 break;
259 case FPE_FLTINV:
260
261 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0)
262 goto not_ieee;
263
264 break;
265 default:
266 /* not an IEEE exception */
267 goto not_ieee;
268 }
269
270 /* get the handling mode */
271 mode = FEX_NOHANDLER;
272 handler = oact.sa_handler; /* for log; just looking, no need to lock */
273 thr_handlers = __fex_get_thr_handlers();
274
275 if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) {
276 mode = thr_handlers[(int)e].__mode;
277 handler = thr_handlers[(int)e].__handler;
278 }
279
280 /* make an entry in the log of retro. diag. if need be */
281 i = ((int)uap->uc_mcontext.fpregs.fpu_fsr >> 5) & 0x1f;
282 __fex_mklog(uap, (char *)sip->si_addr, i, e, mode, (void *)handler);
283
284 /* handle the exception based on the mode */
285 if (mode == FEX_NOHANDLER) {
286 goto not_ieee;
287 } else if (mode == FEX_ABORT) {
288 abort();
289 } else if (mode == FEX_SIGNAL) {
290 handler(sig, sip, uap);
291 return;
292 }
293
294 /* custom or nonstop mode; disable traps and clear flags */
295 __fenv_getfsr(&fsr);
296 __fenv_set_te(fsr, 0);
297 __fenv_set_ex(fsr, 0);
298
299 /*
300 * if interval mode was set, clear it, then substitute the interval
301 * rounding direction and clear ns mode in the fsr
302 */
303 #ifdef __sparcv9
304 gsr = uap->uc_mcontext.asrs[3];
305 #else
306 gsr = 0;
307
308 if (uap->uc_mcontext.xrs.xrs_id == XRS_ID)
309 gsr = (*(unsigned long long *)
310 ((prxregset_t *)uap->uc_mcontext.xrs.xrs_ptr)->pr_un.
311 pr_v8p.pr_filler);
312 #endif
313 gsr = (gsr >> 25) & 7;
314
315 if (gsr & 4) {
316 siamp = (void (*)())siam[0];
317 siamp();
318 tmpfsr = fsr;
319 fsr = (fsr & ~0xc0400000ul) | ((gsr & 3) << 30);
320 }
321
322 __fenv_setfsr(&fsr);
323
324 /* decode the operation */
325 __fex_get_op(sip, uap, &info);
326
327 /* if a custom mode handler is installed, invoke it */
328 if (mode == FEX_CUSTOM) {
329 /* if we got here from feraiseexcept, pass dummy info */
330 addr = (unsigned long)sip->si_addr;
331
332 if (addr >= (unsigned long)feraiseexcept && addr < (unsigned
333 long)fetestexcept) {
334 info.op = fex_other;
335 info.op1.type = info.op2.type = info.res.type =
336 fex_nodata;
337 }
338
339 /*
340 * restore interval mode if it was set, and put the original
341 * rounding direction and ns mode back in the fsr
342 */
343 if (gsr & 4) {
344 __fenv_setfsr(&tmpfsr);
345 siamp = (void (*)())siam[1 + (gsr & 3)];
346 siamp();
347 }
348
349 handler(1 << (int)e, &info);
350
351 /* restore modes in case the user's handler changed them */
352 if (gsr & 4) {
353 siamp = (void (*)())siam[0];
354 siamp();
355 }
356
357 __fenv_setfsr(&fsr);
358 }
359
360 /* stuff the result */
361 __fex_st_result(sip, uap, &info);
362
363 /* "or" in any exception flags and update traps */
364 fsr = uap->uc_mcontext.fpregs.fpu_fsr;
365 fsr |= ((info.flags & 0x1f) << 5);
366 i = __fex_te_needed(thr_handlers, fsr);
367 __fenv_set_te(fsr, i);
368 uap->uc_mcontext.fpregs.fpu_fsr = fsr;
369 return;
370
371 not_ieee:
372 /* revert to the saved handler (if any) */
373 mutex_lock(&hdlr_lock);
374 act = oact;
375 mutex_unlock(&hdlr_lock);
376
377 switch ((unsigned long)act.sa_handler) {
378 case (unsigned long)SIG_DFL:
379 /* simulate trap with no handler installed */
380 sigaction(SIGFPE, &act, NULL);
381 kill(getpid(), SIGFPE);
382 break;
383 #if !defined(__lint)
384 case (unsigned long)SIG_IGN:
385 break;
386 #endif
387 default:
388 act.sa_handler(sig, sip, uap);
389 }
390 }
391 #elif defined(__x86)
392 #if defined(__amd64)
393 #define test_sse_hw 1
394 #else
395 extern int _sse_hw;
396
397 #define test_sse_hw _sse_hw
398 #endif
399
400 #if !defined(REG_PC)
401 #define REG_PC EIP
402 #endif
403
404 /*
405 * If a handling mode is in effect, apply it; otherwise invoke the
406 * saved handler
407 */
408 static void
409 __fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap)
410 {
411 struct fex_handler_data *thr_handlers;
412 struct sigaction act;
413
414 void (*handler)() = NULL, (*simd_handler[4])();
415
416 int mode, simd_mode[4], i, len, accrued, *ap;
417 unsigned int cwsw, oldcwsw, mxcsr, oldmxcsr;
418 enum fex_exception e, simd_e[4];
419 fex_info_t info, simd_info[4];
420 unsigned long addr;
421 siginfo_t osip = *sip;
422 sseinst_t inst;
423
424 /* check for an exception caused by an SSE instruction */
425 if (!(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status & 0x80)) {
426 len = __fex_parse_sse(uap, &inst);
427
428 if (len == 0)
429 goto not_ieee;
430
431 /* disable all traps and clear flags */
432 __fenv_getcwsw(&oldcwsw);
433 cwsw = (oldcwsw & ~0x3f) | 0x003f0000;
434 __fenv_setcwsw(&cwsw);
435 __fenv_getmxcsr(&oldmxcsr);
436 mxcsr = (oldmxcsr & ~0x3f) | 0x1f80;
437 __fenv_setmxcsr(&mxcsr);
438
439 if ((int)inst.op & SIMD) {
440 __fex_get_simd_op(uap, &inst, simd_e, simd_info);
441
442 thr_handlers = __fex_get_thr_handlers();
443 addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC];
444 accrued =
445 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
446 mxcsr;
447
448 e = (enum fex_exception)-1;
449 mode = FEX_NONSTOP;
450
451 for (i = 0; i < 4; i++) {
452 if ((int)simd_e[i] < 0)
453 continue;
454
455 e = simd_e[i];
456 simd_mode[i] = FEX_NOHANDLER;
457 simd_handler[i] = oact.sa_handler;
458
459 if (thr_handlers &&
460 thr_handlers[(int)e].__mode !=
461 FEX_NOHANDLER) {
462 simd_mode[i] =
463 thr_handlers[(int)e].__mode;
464 simd_handler[i] =
465 thr_handlers[(int)e].__handler;
466 }
467
468 accrued &= ~te_bit[(int)e];
469
470 switch (simd_mode[i]) {
471 case FEX_ABORT:
472 mode = FEX_ABORT;
473 break;
474 case FEX_SIGNAL:
475
476 if (mode != FEX_ABORT)
477 mode = FEX_SIGNAL;
478
479 handler = simd_handler[i];
480 break;
481 case FEX_NOHANDLER:
482
483 if (mode != FEX_ABORT && mode !=
484 FEX_SIGNAL)
485 mode = FEX_NOHANDLER;
486
487 break;
488 }
489 }
490
491 if (e == (enum fex_exception)-1) {
492 __fenv_setcwsw(&oldcwsw);
493 __fenv_setmxcsr(&oldmxcsr);
494 goto not_ieee;
495 }
496
497 accrued |=
498 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
499 status;
500 ap = __fex_accrued();
501 accrued |= *ap;
502 accrued &= 0x3d;
503
504 for (i = 0; i < 4; i++) {
505 if ((int)simd_e[i] < 0)
506 continue;
507
508 __fex_mklog(uap, (char *)addr, accrued,
509 simd_e[i], simd_mode[i],
510 (void *)simd_handler[i]);
511 }
512
513 if (mode == FEX_NOHANDLER) {
514 __fenv_setcwsw(&oldcwsw);
515 __fenv_setmxcsr(&oldmxcsr);
516 goto not_ieee;
517 } else if (mode == FEX_ABORT) {
518 abort();
519 } else if (mode == FEX_SIGNAL) {
520 __fenv_setcwsw(&oldcwsw);
521 __fenv_setmxcsr(&oldmxcsr);
522 handler(sig, &osip, uap);
523 return;
524 }
525
526 *ap = 0;
527
528 for (i = 0; i < 4; i++) {
529 if ((int)simd_e[i] < 0)
530 continue;
531
532 if (simd_mode[i] == FEX_CUSTOM) {
533 handler(1 << (int)simd_e[i],
534 &simd_info[i]);
535 __fenv_setcwsw(&cwsw);
536 __fenv_setmxcsr(&mxcsr);
537 }
538 }
539
540 __fex_st_simd_result(uap, &inst, simd_e, simd_info);
541
542 for (i = 0; i < 4; i++) {
543 if ((int)simd_e[i] < 0)
544 continue;
545
546 accrued |= simd_info[i].flags;
547 }
548
549 if ((int)inst.op & INTREG) {
550 /* set MMX mode */
551 #if defined(__amd64)
552 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
553 sw &= ~0x3800;
554 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
555 fctw = 0;
556 #else
557 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
558 state[1] &= ~0x3800;
559 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
560 state[2] = 0;
561 #endif
562 }
563 } else {
564 e = __fex_get_sse_op(uap, &inst, &info);
565
566 if ((int)e < 0) {
567 __fenv_setcwsw(&oldcwsw);
568 __fenv_setmxcsr(&oldmxcsr);
569 goto not_ieee;
570 }
571
572 mode = FEX_NOHANDLER;
573 handler = oact.sa_handler;
574 thr_handlers = __fex_get_thr_handlers();
575
576 if (thr_handlers && thr_handlers[(int)e].__mode !=
577 FEX_NOHANDLER) {
578 mode = thr_handlers[(int)e].__mode;
579 handler = thr_handlers[(int)e].__handler;
580 }
581
582 addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC];
583 accrued =
584 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
585 mxcsr & ~te_bit[(int)e];
586 accrued |=
587 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
588 status;
589 ap = __fex_accrued();
590 accrued |= *ap;
591 accrued &= 0x3d;
592 __fex_mklog(uap, (char *)addr, accrued, e, mode,
593 (void *)handler);
594
595 if (mode == FEX_NOHANDLER) {
596 __fenv_setcwsw(&oldcwsw);
597 __fenv_setmxcsr(&oldmxcsr);
598 goto not_ieee;
599 } else if (mode == FEX_ABORT) {
600 abort();
601 } else if (mode == FEX_SIGNAL) {
602 __fenv_setcwsw(&oldcwsw);
603 __fenv_setmxcsr(&oldmxcsr);
604 handler(sig, &osip, uap);
605 return;
606 } else if (mode == FEX_CUSTOM) {
607 *ap = 0;
608
609 if (addr >= (unsigned long)feraiseexcept &&
610 addr < (unsigned long)fetestexcept) {
611 info.op = fex_other;
612 info.op1.type = info.op2.type =
613 info.res.type = fex_nodata;
614 }
615
616 handler(1 << (int)e, &info);
617 __fenv_setcwsw(&cwsw);
618 __fenv_setmxcsr(&mxcsr);
619 }
620
621 __fex_st_sse_result(uap, &inst, e, &info);
622 accrued |= info.flags;
623
624 #if defined(__amd64)
625 /*
626 * In 64-bit mode, the 32-bit convert-to-integer
627 * instructions zero the upper 32 bits of the
628 * destination. (We do this here and not in
629 * __fex_st_sse_result because __fex_st_sse_result
630 * can be called from __fex_st_simd_result, too.)
631 */
632 if (inst.op == cvtss2si || inst.op == cvttss2si ||
633 inst.op == cvtsd2si || inst.op == cvttsd2si)
634 inst.op1->i[1] = 0;
635 #endif
636 }
637
638 /* advance the pc past the SSE instruction */
639 uap->uc_mcontext.gregs[REG_PC] += len;
640 goto update_state;
641 }
642
643 /* determine which exception occurred */
644 __fex_get_x86_exc(sip, uap);
645
646 switch (sip->si_code) {
647 case FPE_FLTDIV:
648 e = fex_division;
649 break;
650 case FPE_FLTOVF:
651 e = fex_overflow;
652 break;
653 case FPE_FLTUND:
654 e = fex_underflow;
655 break;
656 case FPE_FLTRES:
657 e = fex_inexact;
658 break;
659 case FPE_FLTINV:
660
661 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0)
662 goto not_ieee;
663
664 break;
665 default:
666 /* not an IEEE exception */
667 goto not_ieee;
668 }
669
670 /* get the handling mode */
671 mode = FEX_NOHANDLER;
672 handler = oact.sa_handler; /* for log; just looking, no need to lock */
673 thr_handlers = __fex_get_thr_handlers();
674
675 if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) {
676 mode = thr_handlers[(int)e].__mode;
677 handler = thr_handlers[(int)e].__handler;
678 }
679
680 /* make an entry in the log of retro. diag. if need be */
681 #if defined(__amd64)
682 addr = (unsigned
683 long)uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rip;
684 #else
685 addr = (unsigned
686 long)uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[3];
687 #endif
688 accrued = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status &
689 ~te_bit[(int)e];
690
691 if (test_sse_hw)
692 accrued |=
693 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr;
694
695 ap = __fex_accrued();
696 accrued |= *ap;
697 accrued &= 0x3d;
698 __fex_mklog(uap, (char *)addr, accrued, e, mode, (void *)handler);
699
700 /* handle the exception based on the mode */
701 if (mode == FEX_NOHANDLER) {
702 goto not_ieee;
703 } else if (mode == FEX_ABORT) {
704 abort();
705 } else if (mode == FEX_SIGNAL) {
706 handler(sig, &osip, uap);
707 return;
708 }
709
710 /* disable all traps and clear flags */
711 __fenv_getcwsw(&cwsw);
712 cwsw = (cwsw & ~0x3f) | 0x003f0000;
713 __fenv_setcwsw(&cwsw);
714
715 if (test_sse_hw) {
716 __fenv_getmxcsr(&mxcsr);
717 mxcsr = (mxcsr & ~0x3f) | 0x1f80;
718 __fenv_setmxcsr(&mxcsr);
719 }
720
721 *ap = 0;
722
723 /* decode the operation */
724 __fex_get_op(sip, uap, &info);
725
726 /* if a custom mode handler is installed, invoke it */
727 if (mode == FEX_CUSTOM) {
728 /* if we got here from feraiseexcept, pass dummy info */
729 if (addr >= (unsigned long)feraiseexcept && addr < (unsigned
730 long)fetestexcept) {
731 info.op = fex_other;
732 info.op1.type = info.op2.type = info.res.type =
733 fex_nodata;
734 }
735
736 handler(1 << (int)e, &info);
737
738 /* restore modes in case the user's handler changed them */
739 __fenv_setcwsw(&cwsw);
740
741 if (test_sse_hw)
742 __fenv_setmxcsr(&mxcsr);
743 }
744
745 /* stuff the result */
746 __fex_st_result(sip, uap, &info);
747 accrued |= info.flags;
748
749 update_state:
750 accrued &= 0x3d;
751 i = __fex_te_needed(thr_handlers, accrued);
752 *ap = accrued & i;
753 #if defined(__amd64)
754 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw &= ~0x3d;
755 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= (accrued & ~i);
756 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw |= 0x3d;
757 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw &= ~i;
758 #else
759 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] &= ~0x3d;
760 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] |= (accrued &
761 ~i);
762 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] |= 0x3d;
763 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] &= ~i;
764 #endif
765
766 if (test_sse_hw) {
767 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &= ~0x3d;
768 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr |=
769 0x1e80 | (accrued & ~i);
770 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &= ~(i <<
771 7);
772 }
773
774 return;
775
776 not_ieee:
777 /* revert to the saved handler (if any) */
778 mutex_lock(&hdlr_lock);
779 act = oact;
780 mutex_unlock(&hdlr_lock);
781
782 switch ((unsigned long)act.sa_handler) {
783 case (unsigned long)SIG_DFL:
784 /* simulate trap with no handler installed */
785 sigaction(SIGFPE, &act, NULL);
786 kill(getpid(), SIGFPE);
787 break;
788 #if !defined(__lint)
789 case (unsigned long)SIG_IGN:
790 break;
791 #endif
792 default:
793 act.sa_handler(sig, &osip, uap);
794 }
795 }
796 #else
797 #error Unknown architecture
798 #endif
799
800 /*
801 * Return a pointer to the thread-specific handler data, and
802 * initialize it if necessary
803 */
804 struct fex_handler_data *
805 __fex_get_thr_handlers()
806 {
807 struct fex_handler_data *ptr;
808 unsigned long fsr;
809 int i, te;
810
811 if (thr_main()) {
812 if (!handlers_initialized) {
813 /*
814 * initialize to FEX_NOHANDLER if trap is enabled,
815 * FEX_NONSTOP if trap is disabled
816 */
817 __fenv_getfsr(&fsr);
818 te = (int)__fenv_get_te(fsr);
819
820 for (i = 0; i < FEX_NUM_EXC; i++)
821 main_handlers[i].__mode = ((te & te_bit[i]) ?
822 FEX_NOHANDLER : FEX_NONSTOP);
823
824 handlers_initialized = 1;
825 }
826
827 return (main_handlers);
828 } else {
829 ptr = NULL;
830 mutex_lock(&handlers_key_lock);
831
832 if (thr_getspecific(handlers_key, (void **)&ptr) != 0 &&
833 thr_keycreate(&handlers_key, free) != 0) {
834 mutex_unlock(&handlers_key_lock);
835 return (NULL);
836 }
837
838 mutex_unlock(&handlers_key_lock);
839
840 if (!ptr) {
841 if ((ptr = malloc(sizeof (fex_handler_t))) == NULL)
842 return (NULL);
843
844 if (thr_setspecific(handlers_key, (void *)ptr) != 0) {
845 (void) free(ptr);
846 return (NULL);
847 }
848
849 /*
850 * initialize to FEX_NOHANDLER if trap is enabled,
851 * FEX_NONSTOP if trap is disabled
852 */
853 __fenv_getfsr(&fsr);
854 te = (int)__fenv_get_te(fsr);
855
856 for (i = 0; i < FEX_NUM_EXC; i++)
857 ptr[i].__mode = ((te & te_bit[i]) ?
858 FEX_NOHANDLER : FEX_NONSTOP);
859 }
860
861 return (ptr);
862 }
863 }
864
865 /*
866 * Update the trap enable bits according to the selected modes
867 */
868 void
869 __fex_update_te()
870 {
871 struct fex_handler_data *thr_handlers;
872 struct sigaction act, tmpact;
873 sigset_t blocked;
874 unsigned long fsr;
875 int te;
876
877 /* determine which traps are needed */
878 thr_handlers = __fex_get_thr_handlers();
879 __fenv_getfsr(&fsr);
880 te = __fex_te_needed(thr_handlers, fsr);
881
882 /* install __fex_hdlr as necessary */
883 if (!hdlr_installed && te) {
884 act.sa_handler = __fex_hdlr;
885 sigemptyset(&act.sa_mask);
886 act.sa_flags = SA_SIGINFO;
887 sigaction(SIGFPE, &act, &tmpact);
888
889 if (tmpact.sa_handler != __fex_hdlr) {
890 mutex_lock(&hdlr_lock);
891 oact = tmpact;
892 mutex_unlock(&hdlr_lock);
893 }
894
895 hdlr_installed = 1;
896 }
897
898 /* set the new trap enable bits (only if SIGFPE is not blocked) */
899 if (sigprocmask(0, NULL, &blocked) == 0 && !sigismember(&blocked,
900 SIGFPE)) {
901 __fenv_set_te(fsr, te);
902 __fenv_setfsr(&fsr);
903 }
904
905 /* synchronize with libmtsk */
906 __mt_fex_sync = __fex_sync_with_libmtsk;
907
908 /* synchronize with other projects */
909 __libm_mt_fex_sync = __fex_sync_with_threads;
910 }
|