25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * CDDL HEADER START
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis *
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * The contents of this file are subject to the terms of the
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Common Development and Distribution License (the "License").
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * You may not use this file except in compliance with the License.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis *
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * or http://www.opensolaris.org/os/licensing.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * See the License for the specific language governing permissions
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * and limitations under the License.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis *
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * When distributing Covered Code, include this CDDL HEADER in each
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * If applicable, add the following below this CDDL HEADER, with the
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * fields enclosed by brackets "[]" replaced with your own identifying
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * information: Portions Copyright [yyyy] [name of copyright owner]
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis *
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * CDDL HEADER END
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Use is subject to license terms.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#undef lint
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include <signal.h>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include <siginfo.h>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include <ucontext.h>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include <stdio.h>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include <stdlib.h>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include <unistd.h>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include <thread.h>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include <math.h>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if defined(__SUNPRO_C)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include <sunmath.h>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include <fenv.h>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include "fex_handler.h"
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include "fenv_inlines.h"
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if defined(__sparc) && !defined(__sparcv9)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#include <sys/procfs.h>
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/* 2.x signal.h doesn't declare sigemptyset or sigismember
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if they're #defined (see sys/signal.h) */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisextern int sigemptyset(sigset_t *);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisextern int sigismember(const sigset_t *, int);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/* external globals */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisvoid (*__mt_fex_sync)() = NULL; /* for synchronization with libmtsk */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#pragma weak __mt_fex_sync
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisvoid (*__libm_mt_fex_sync)() = NULL; /* new, improved version of above */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#pragma weak __libm_mt_fex_sync
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/* private variables */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic fex_handler_t main_handlers;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic int handlers_initialized = 0;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic thread_key_t handlers_key;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic mutex_t handlers_key_lock = DEFAULTMUTEX;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic struct sigaction oact = { 0, SIG_DFL };
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic mutex_t hdlr_lock = DEFAULTMUTEX;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic int hdlr_installed = 0;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/* private const data */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic const int te_bit[FEX_NUM_EXC] = {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 1 << fp_trap_inexact,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 1 << fp_trap_division,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 1 << fp_trap_underflow,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 1 << fp_trap_overflow,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 1 << fp_trap_invalid,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 1 << fp_trap_invalid,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 1 << fp_trap_invalid,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 1 << fp_trap_invalid,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 1 << fp_trap_invalid,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 1 << fp_trap_invalid,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 1 << fp_trap_invalid,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 1 << fp_trap_invalid
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis};
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* Return the traps to be enabled given the current handling modes
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* and flags
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis*/
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic int
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis__fex_te_needed(struct fex_handler_data *thr_handlers, unsigned long fsr)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis{
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis int i, ex, te;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* set traps for handling modes */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis te = 0;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis for (i = 0; i < FEX_NUM_EXC; i++)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (thr_handlers[i].__mode != FEX_NONSTOP)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis te |= te_bit[i];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* add traps for retrospective diagnostics */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (fex_get_log()) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ex = (int)__fenv_get_ex(fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (!(ex & FE_INEXACT))
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis te |= (1 << fp_trap_inexact);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (!(ex & FE_UNDERFLOW))
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis te |= (1 << fp_trap_underflow);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (!(ex & FE_OVERFLOW))
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis te |= (1 << fp_trap_overflow);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (!(ex & FE_DIVBYZERO))
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis te |= (1 << fp_trap_division);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (!(ex & FE_INVALID))
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis te |= (1 << fp_trap_invalid);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis return te;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis}
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* The following function synchronizes with libmtsk (SPARC only, for now)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis*/
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic void
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis__fex_sync_with_libmtsk(int begin, int master)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis{
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis static fenv_t master_env;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis static int env_initialized = 0;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis static mutex_t env_lock = DEFAULTMUTEX;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (begin) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_lock(&env_lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (master) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis (void) fegetenv(&master_env);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis env_initialized = 1;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis else if (env_initialized)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis (void) fesetenv(&master_env);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_unlock(&env_lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis else if (master && fex_get_log())
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_update_te();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis}
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* The following function may be used for synchronization with any
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* internal project that manages multiple threads
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis*/
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisenum __libm_mt_fex_sync_actions {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __libm_mt_fex_start_master = 0,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __libm_mt_fex_start_slave,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __libm_mt_fex_finish_master,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __libm_mt_fex_finish_slave
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis};
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstruct __libm_mt_fex_sync_data {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fenv_t master_env;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis int initialized;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_t lock;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis};
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic void
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis__fex_sync_with_threads(enum __libm_mt_fex_sync_actions action,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis struct __libm_mt_fex_sync_data *thr_env)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis{
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis switch (action) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case __libm_mt_fex_start_master:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_lock(&thr_env->lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis (void) fegetenv(&thr_env->master_env);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis thr_env->initialized = 1;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_unlock(&thr_env->lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case __libm_mt_fex_start_slave:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_lock(&thr_env->lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (thr_env->initialized)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis (void) fesetenv(&thr_env->master_env);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_unlock(&thr_env->lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case __libm_mt_fex_finish_master:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if defined(__x86)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_update_te();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#else
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (fex_get_log())
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_update_te();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case __libm_mt_fex_finish_slave:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if defined(__x86)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* clear traps, making all accrued flags visible in status word */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis unsigned long fsr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_getfsr(&fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_set_te(fsr, 0);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setfsr(&fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis}
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if defined(__sparc)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* Code for setting or clearing interval mode on US-III and above.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* This is embedded as data so we don't have to mark the library
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* as a v8plusb/v9b object. (I could have just used one entry and
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* modified the second word to set the bits I want, but that would
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* have required another mutex.)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis*/
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic const unsigned int siam[][2] = {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis { 0x81c3e008, 0x81b01020 }, /* retl, siam 0 */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis { 0x81c3e008, 0x81b01024 }, /* retl, siam 4 */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis { 0x81c3e008, 0x81b01025 }, /* retl, siam 5 */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis { 0x81c3e008, 0x81b01026 }, /* retl, siam 6 */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis { 0x81c3e008, 0x81b01027 } /* retl, siam 7 */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis};
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* If a handling mode is in effect, apply it; otherwise invoke the
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* saved handler
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis*/
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic void
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis__fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis{
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis struct fex_handler_data *thr_handlers;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis struct sigaction act;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis void (*handler)(), (*siamp)();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis int mode, i;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis enum fex_exception e;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fex_info_t info;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis unsigned long fsr, tmpfsr, addr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis unsigned int gsr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* determine which exception occurred */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis switch (sip->si_code) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FPE_FLTDIV:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis e = fex_division;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FPE_FLTOVF:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis e = fex_overflow;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FPE_FLTUND:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis e = fex_underflow;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FPE_FLTRES:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis e = fex_inexact;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FPE_FLTINV:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis goto not_ieee;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis default:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* not an IEEE exception */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis goto not_ieee;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* get the handling mode */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mode = FEX_NOHANDLER;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler = oact.sa_handler; /* for log; just looking, no need to lock */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis thr_handlers = __fex_get_thr_handlers();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mode = thr_handlers[(int)e].__mode;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler = thr_handlers[(int)e].__handler;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* make an entry in the log of retro. diag. if need be */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis i = ((int)uap->uc_mcontext.fpregs.fpu_fsr >> 5) & 0x1f;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_mklog(uap, (char *)sip->si_addr, i, e, mode, (void *)handler);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* handle the exception based on the mode */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (mode == FEX_NOHANDLER)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis goto not_ieee;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis else if (mode == FEX_ABORT)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis abort();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis else if (mode == FEX_SIGNAL) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler(sig, sip, uap);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis return;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* custom or nonstop mode; disable traps and clear flags */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_getfsr(&fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_set_te(fsr, 0);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_set_ex(fsr, 0);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* if interval mode was set, clear it, then substitute the
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis interval rounding direction and clear ns mode in the fsr */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#ifdef __sparcv9
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis gsr = uap->uc_mcontext.asrs[3];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#else
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis gsr = 0;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (uap->uc_mcontext.xrs.xrs_id == XRS_ID)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis gsr = (*(unsigned long long*)((prxregset_t*)uap->uc_mcontext.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis xrs.xrs_ptr)->pr_un.pr_v8p.pr_filler);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis gsr = (gsr >> 25) & 7;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (gsr & 4) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis siamp = (void (*)()) siam[0];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis siamp();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis tmpfsr = fsr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fsr = (fsr & ~0xc0400000ul) | ((gsr & 3) << 30);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setfsr(&fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* decode the operation */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_get_op(sip, uap, &info);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* if a custom mode handler is installed, invoke it */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (mode == FEX_CUSTOM) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* if we got here from feraiseexcept, pass dummy info */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis addr = (unsigned long)sip->si_addr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (addr >= (unsigned long)feraiseexcept &&
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis addr < (unsigned long)fetestexcept) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis info.op = fex_other;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis info.op1.type = info.op2.type = info.res.type =
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fex_nodata;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* restore interval mode if it was set, and put the original
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis rounding direction and ns mode back in the fsr */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (gsr & 4) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setfsr(&tmpfsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis siamp = (void (*)()) siam[1 + (gsr & 3)];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis siamp();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler(1 << (int)e, &info);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* restore modes in case the user's handler changed them */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (gsr & 4) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis siamp = (void (*)()) siam[0];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis siamp();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setfsr(&fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* stuff the result */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_st_result(sip, uap, &info);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* "or" in any exception flags and update traps */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fsr = uap->uc_mcontext.fpregs.fpu_fsr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fsr |= ((info.flags & 0x1f) << 5);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis i = __fex_te_needed(thr_handlers, fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_set_te(fsr, i);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fpu_fsr = fsr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis return;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisnot_ieee:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* revert to the saved handler (if any) */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_lock(&hdlr_lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis act = oact;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_unlock(&hdlr_lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis switch ((unsigned long)act.sa_handler) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case (unsigned long)SIG_DFL:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* simulate trap with no handler installed */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis sigaction(SIGFPE, &act, NULL);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis kill(getpid(), SIGFPE);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if !defined(__lint)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case (unsigned long)SIG_IGN:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis default:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis act.sa_handler(sig, sip, uap);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis}
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#elif defined(__x86)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if defined(__amd64)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#define test_sse_hw 1
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#else
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisextern int _sse_hw;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#define test_sse_hw _sse_hw
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if !defined(REG_PC)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#define REG_PC EIP
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* If a handling mode is in effect, apply it; otherwise invoke the
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* saved handler
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis*/
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic void
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis__fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis{
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis struct fex_handler_data *thr_handlers;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis struct sigaction act;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis void (*handler)() = NULL, (*simd_handler[4])();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis int mode, simd_mode[4], i, len, accrued, *ap;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis unsigned int cwsw, oldcwsw, mxcsr, oldmxcsr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis enum fex_exception e, simd_e[4];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fex_info_t info, simd_info[4];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis unsigned long addr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis siginfo_t osip = *sip;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis sseinst_t inst;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* check for an exception caused by an SSE instruction */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (!(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status & 0x80)) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis len = __fex_parse_sse(uap, &inst);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (len == 0)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis goto not_ieee;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* disable all traps and clear flags */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_getcwsw(&oldcwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis cwsw = (oldcwsw & ~0x3f) | 0x003f0000;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setcwsw(&cwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_getmxcsr(&oldmxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mxcsr = (oldmxcsr & ~0x3f) | 0x1f80;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setmxcsr(&mxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if ((int)inst.op & SIMD) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_get_simd_op(uap, &inst, simd_e, simd_info);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis thr_handlers = __fex_get_thr_handlers();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued = uap->uc_mcontext.fpregs.fp_reg_set.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fpchip_state.mxcsr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis e = (enum fex_exception)-1;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mode = FEX_NONSTOP;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis for (i = 0; i < 4; i++) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if ((int)simd_e[i] < 0)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis continue;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis e = simd_e[i];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis simd_mode[i] = FEX_NOHANDLER;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis simd_handler[i] = oact.sa_handler;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (thr_handlers &&
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis thr_handlers[(int)e].__mode !=
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis FEX_NOHANDLER) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis simd_mode[i] =
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis thr_handlers[(int)e].__mode;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis simd_handler[i] =
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis thr_handlers[(int)e].__handler;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued &= ~te_bit[(int)e];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis switch (simd_mode[i]) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FEX_ABORT:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mode = FEX_ABORT;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FEX_SIGNAL:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (mode != FEX_ABORT)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mode = FEX_SIGNAL;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler = simd_handler[i];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FEX_NOHANDLER:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (mode != FEX_ABORT && mode !=
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis FEX_SIGNAL)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mode = FEX_NOHANDLER;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (e == (enum fex_exception)-1) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setcwsw(&oldcwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setmxcsr(&oldmxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis goto not_ieee;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued |= uap->uc_mcontext.fpregs.fp_reg_set.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fpchip_state.status;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ap = __fex_accrued();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued |= *ap;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued &= 0x3d;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis for (i = 0; i < 4; i++) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if ((int)simd_e[i] < 0)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis continue;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_mklog(uap, (char *)addr, accrued,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis simd_e[i], simd_mode[i],
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis (void *)simd_handler[i]);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (mode == FEX_NOHANDLER) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setcwsw(&oldcwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setmxcsr(&oldmxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis goto not_ieee;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis } else if (mode == FEX_ABORT) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis abort();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis } else if (mode == FEX_SIGNAL) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setcwsw(&oldcwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setmxcsr(&oldmxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler(sig, &osip, uap);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis return;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis *ap = 0;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis for (i = 0; i < 4; i++) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if ((int)simd_e[i] < 0)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis continue;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (simd_mode[i] == FEX_CUSTOM) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler(1 << (int)simd_e[i],
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis &simd_info[i]);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setcwsw(&cwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setmxcsr(&mxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_st_simd_result(uap, &inst, simd_e, simd_info);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis for (i = 0; i < 4; i++) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if ((int)simd_e[i] < 0)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis continue;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued |= simd_info[i].flags;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if ((int)inst.op & INTREG) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* set MMX mode */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if defined(__amd64)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fpchip_state.sw &= ~0x3800;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fpchip_state.fctw = 0;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#else
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fpchip_state.state[1] &= ~0x3800;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fpchip_state.state[2] = 0;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis } else {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis e = __fex_get_sse_op(uap, &inst, &info);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if ((int)e < 0) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setcwsw(&oldcwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setmxcsr(&oldmxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis goto not_ieee;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mode = FEX_NOHANDLER;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler = oact.sa_handler;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis thr_handlers = __fex_get_thr_handlers();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (thr_handlers && thr_handlers[(int)e].__mode !=
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis FEX_NOHANDLER) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mode = thr_handlers[(int)e].__mode;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler = thr_handlers[(int)e].__handler;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued = uap->uc_mcontext.fpregs.fp_reg_set.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fpchip_state.mxcsr & ~te_bit[(int)e];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued |= uap->uc_mcontext.fpregs.fp_reg_set.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fpchip_state.status;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ap = __fex_accrued();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued |= *ap;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued &= 0x3d;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_mklog(uap, (char *)addr, accrued, e, mode,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis (void *)handler);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (mode == FEX_NOHANDLER) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setcwsw(&oldcwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setmxcsr(&oldmxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis goto not_ieee;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis } else if (mode == FEX_ABORT) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis abort();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis } else if (mode == FEX_SIGNAL) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setcwsw(&oldcwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setmxcsr(&oldmxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler(sig, &osip, uap);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis return;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis } else if (mode == FEX_CUSTOM) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis *ap = 0;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (addr >= (unsigned long)feraiseexcept &&
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis addr < (unsigned long)fetestexcept) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis info.op = fex_other;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis info.op1.type = info.op2.type =
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis info.res.type = fex_nodata;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler(1 << (int)e, &info);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setcwsw(&cwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setmxcsr(&mxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_st_sse_result(uap, &inst, e, &info);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued |= info.flags;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if defined(__amd64)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /*
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * In 64-bit mode, the 32-bit convert-to-integer
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * instructions zero the upper 32 bits of the
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * destination. (We do this here and not in
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * __fex_st_sse_result because __fex_st_sse_result
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * can be called from __fex_st_simd_result, too.)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (inst.op == cvtss2si || inst.op == cvttss2si ||
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis inst.op == cvtsd2si || inst.op == cvttsd2si)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis inst.op1->i[1] = 0;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* advance the pc past the SSE instruction */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.gregs[REG_PC] += len;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis goto update_state;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* determine which exception occurred */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_get_x86_exc(sip, uap);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis switch (sip->si_code) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FPE_FLTDIV:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis e = fex_division;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FPE_FLTOVF:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis e = fex_overflow;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FPE_FLTUND:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis e = fex_underflow;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FPE_FLTRES:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis e = fex_inexact;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case FPE_FLTINV:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis goto not_ieee;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis default:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* not an IEEE exception */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis goto not_ieee;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* get the handling mode */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mode = FEX_NOHANDLER;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler = oact.sa_handler; /* for log; just looking, no need to lock */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis thr_handlers = __fex_get_thr_handlers();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mode = thr_handlers[(int)e].__mode;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler = thr_handlers[(int)e].__handler;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* make an entry in the log of retro. diag. if need be */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if defined(__amd64)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis addr = (unsigned long)uap->uc_mcontext.fpregs.fp_reg_set.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fpchip_state.rip;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#else
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis addr = (unsigned long)uap->uc_mcontext.fpregs.fp_reg_set.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fpchip_state.state[3];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status &
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ~te_bit[(int)e];
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (test_sse_hw)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued |= uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mxcsr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ap = __fex_accrued();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued |= *ap;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued &= 0x3d;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_mklog(uap, (char *)addr, accrued, e, mode, (void *)handler);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* handle the exception based on the mode */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (mode == FEX_NOHANDLER)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis goto not_ieee;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis else if (mode == FEX_ABORT)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis abort();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis else if (mode == FEX_SIGNAL) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler(sig, &osip, uap);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis return;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* disable all traps and clear flags */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_getcwsw(&cwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis cwsw = (cwsw & ~0x3f) | 0x003f0000;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setcwsw(&cwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (test_sse_hw) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_getmxcsr(&mxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mxcsr = (mxcsr & ~0x3f) | 0x1f80;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setmxcsr(&mxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis *ap = 0;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* decode the operation */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_get_op(sip, uap, &info);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* if a custom mode handler is installed, invoke it */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (mode == FEX_CUSTOM) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* if we got here from feraiseexcept, pass dummy info */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (addr >= (unsigned long)feraiseexcept &&
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis addr < (unsigned long)fetestexcept) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis info.op = fex_other;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis info.op1.type = info.op2.type = info.res.type =
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis fex_nodata;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handler(1 << (int)e, &info);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* restore modes in case the user's handler changed them */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setcwsw(&cwsw);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (test_sse_hw)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setmxcsr(&mxcsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* stuff the result */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fex_st_result(sip, uap, &info);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued |= info.flags;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisupdate_state:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis accrued &= 0x3d;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis i = __fex_te_needed(thr_handlers, accrued);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis *ap = accrued & i;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if defined(__amd64)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw &= ~0x3d;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= (accrued & ~i);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw |= 0x3d;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw &= ~i;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#else
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] &= ~0x3d;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] |=
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis (accrued & ~i);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] |= 0x3d;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] &= ~i;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (test_sse_hw) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &= ~0x3d;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr |=
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis 0x1e80 | (accrued & ~i);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &=
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ~(i << 7);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis return;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisnot_ieee:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* revert to the saved handler (if any) */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_lock(&hdlr_lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis act = oact;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_unlock(&hdlr_lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis switch ((unsigned long)act.sa_handler) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case (unsigned long)SIG_DFL:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* simulate trap with no handler installed */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis sigaction(SIGFPE, &act, NULL);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis kill(getpid(), SIGFPE);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#if !defined(__lint)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis case (unsigned long)SIG_IGN:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis break;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis default:
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis act.sa_handler(sig, &osip, uap);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis}
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#else
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#error Unknown architecture
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* Return a pointer to the thread-specific handler data, and
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* initialize it if necessary
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis*/
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstruct fex_handler_data *
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis__fex_get_thr_handlers()
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis{
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis struct fex_handler_data *ptr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis unsigned long fsr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis int i, te;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (thr_main()) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (!handlers_initialized) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* initialize to FEX_NOHANDLER if trap is enabled,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis FEX_NONSTOP if trap is disabled */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_getfsr(&fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis te = (int)__fenv_get_te(fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis for (i = 0; i < FEX_NUM_EXC; i++)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis main_handlers[i].__mode =
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ((te & te_bit[i])? FEX_NOHANDLER : FEX_NONSTOP);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis handlers_initialized = 1;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis return main_handlers;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis else {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ptr = NULL;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_lock(&handlers_key_lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (thr_getspecific(handlers_key, (void **)&ptr) != 0 &&
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis thr_keycreate(&handlers_key, free) != 0) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_unlock(&handlers_key_lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis return NULL;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_unlock(&handlers_key_lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (!ptr) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if ((ptr = (struct fex_handler_data *)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis malloc(sizeof(fex_handler_t))) == NULL) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis return NULL;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (thr_setspecific(handlers_key, (void *)ptr) != 0) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis (void)free(ptr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis return NULL;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* initialize to FEX_NOHANDLER if trap is enabled,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis FEX_NONSTOP if trap is disabled */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_getfsr(&fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis te = (int)__fenv_get_te(fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis for (i = 0; i < FEX_NUM_EXC; i++)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis ptr[i].__mode = ((te & te_bit[i])? FEX_NOHANDLER : FEX_NONSTOP);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis return ptr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis}
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* Update the trap enable bits according to the selected modes
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis*/
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisvoid
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis__fex_update_te()
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis{
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis struct fex_handler_data *thr_handlers;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis struct sigaction act, tmpact;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis sigset_t blocked;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis unsigned long fsr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis int te;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* determine which traps are needed */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis thr_handlers = __fex_get_thr_handlers();
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_getfsr(&fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis te = __fex_te_needed(thr_handlers, fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* install __fex_hdlr as necessary */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (!hdlr_installed && te) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis act.sa_handler = __fex_hdlr;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis sigemptyset(&act.sa_mask);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis act.sa_flags = SA_SIGINFO;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis sigaction(SIGFPE, &act, &tmpact);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (tmpact.sa_handler != __fex_hdlr)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_lock(&hdlr_lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis oact = tmpact;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis mutex_unlock(&hdlr_lock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis hdlr_installed = 1;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* set the new trap enable bits (only if SIGFPE is not blocked) */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis if (sigprocmask(0, NULL, &blocked) == 0 &&
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis !sigismember(&blocked, SIGFPE)) {
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_set_te(fsr, te);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __fenv_setfsr(&fsr);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis }
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* synchronize with libmtsk */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __mt_fex_sync = __fex_sync_with_libmtsk;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /* synchronize with other projects */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis __libm_mt_fex_sync = __fex_sync_with_threads;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis}