17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 227af88ac7SKuriakose Kuruvilla * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 267c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 277c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 307c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 317c478bd9Sstevel@tonic-gate 327af88ac7SKuriakose Kuruvilla /* 337af88ac7SKuriakose Kuruvilla * Copyright (c) 2009, Intel Corporation. 347af88ac7SKuriakose Kuruvilla * All rights reserved. 357af88ac7SKuriakose Kuruvilla */ 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <sys/types.h> 387c478bd9Sstevel@tonic-gate #include <sys/param.h> 397c478bd9Sstevel@tonic-gate #include <sys/signal.h> 407c478bd9Sstevel@tonic-gate #include <sys/regset.h> 417c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 427c478bd9Sstevel@tonic-gate #include <sys/psw.h> 437c478bd9Sstevel@tonic-gate #include <sys/trap.h> 447c478bd9Sstevel@tonic-gate #include <sys/fault.h> 457c478bd9Sstevel@tonic-gate #include <sys/systm.h> 467c478bd9Sstevel@tonic-gate #include <sys/user.h> 477c478bd9Sstevel@tonic-gate #include <sys/file.h> 487c478bd9Sstevel@tonic-gate #include <sys/proc.h> 497c478bd9Sstevel@tonic-gate #include <sys/pcb.h> 507c478bd9Sstevel@tonic-gate #include <sys/lwp.h> 517c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 527c478bd9Sstevel@tonic-gate #include <sys/thread.h> 537c478bd9Sstevel@tonic-gate #include <sys/disp.h> 547c478bd9Sstevel@tonic-gate #include <sys/fp.h> 557c478bd9Sstevel@tonic-gate #include <sys/siginfo.h> 567c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 577c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 587c478bd9Sstevel@tonic-gate #include <sys/debug.h> 597c478bd9Sstevel@tonic-gate #include <sys/x86_archext.h> 607c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 617af88ac7SKuriakose Kuruvilla #include <sys/cmn_err.h> 627af88ac7SKuriakose Kuruvilla 637af88ac7SKuriakose Kuruvilla /* Legacy fxsave layout + xsave header + ymm */ 647af88ac7SKuriakose Kuruvilla #define AVX_XSAVE_SIZE (512 + 64 + 256) 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate /*CSTYLED*/ 677c478bd9Sstevel@tonic-gate #pragma align 16 (sse_initial) 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate /* 707c478bd9Sstevel@tonic-gate * Initial kfpu state for SSE/SSE2 used by fpinit() 717c478bd9Sstevel@tonic-gate */ 727c478bd9Sstevel@tonic-gate const struct fxsave_state sse_initial = { 737c478bd9Sstevel@tonic-gate FPU_CW_INIT, /* fx_fcw */ 747c478bd9Sstevel@tonic-gate 0, /* fx_fsw */ 757c478bd9Sstevel@tonic-gate 0, /* fx_fctw */ 767c478bd9Sstevel@tonic-gate 0, /* fx_fop */ 777c478bd9Sstevel@tonic-gate #if defined(__amd64) 787c478bd9Sstevel@tonic-gate 0, /* fx_rip */ 797c478bd9Sstevel@tonic-gate 0, /* fx_rdp */ 807c478bd9Sstevel@tonic-gate #else 817c478bd9Sstevel@tonic-gate 0, /* fx_eip */ 827c478bd9Sstevel@tonic-gate 0, /* fx_cs */ 837c478bd9Sstevel@tonic-gate 0, /* __fx_ign0 */ 847c478bd9Sstevel@tonic-gate 0, /* fx_dp */ 857c478bd9Sstevel@tonic-gate 0, /* fx_ds */ 867c478bd9Sstevel@tonic-gate 0, /* __fx_ign1 */ 877c478bd9Sstevel@tonic-gate #endif /* __amd64 */ 887c478bd9Sstevel@tonic-gate SSE_MXCSR_INIT /* fx_mxcsr */ 897c478bd9Sstevel@tonic-gate /* rest of structure is zero */ 907c478bd9Sstevel@tonic-gate }; 917c478bd9Sstevel@tonic-gate 927af88ac7SKuriakose Kuruvilla /*CSTYLED*/ 937af88ac7SKuriakose Kuruvilla #pragma align 64 (avx_initial) 947af88ac7SKuriakose Kuruvilla 957af88ac7SKuriakose Kuruvilla /* 967af88ac7SKuriakose Kuruvilla * Initial kfpu state for AVX used by fpinit() 977af88ac7SKuriakose Kuruvilla */ 987af88ac7SKuriakose Kuruvilla const struct xsave_state avx_initial = { 997af88ac7SKuriakose Kuruvilla /* 1007af88ac7SKuriakose Kuruvilla * The definition below needs to be identical with sse_initial 1017af88ac7SKuriakose Kuruvilla * defined above. 1027af88ac7SKuriakose Kuruvilla */ 1037af88ac7SKuriakose Kuruvilla { 1047af88ac7SKuriakose Kuruvilla FPU_CW_INIT, /* fx_fcw */ 1057af88ac7SKuriakose Kuruvilla 0, /* fx_fsw */ 1067af88ac7SKuriakose Kuruvilla 0, /* fx_fctw */ 1077af88ac7SKuriakose Kuruvilla 0, /* fx_fop */ 1087af88ac7SKuriakose Kuruvilla #if defined(__amd64) 1097af88ac7SKuriakose Kuruvilla 0, /* fx_rip */ 1107af88ac7SKuriakose Kuruvilla 0, /* fx_rdp */ 1117af88ac7SKuriakose Kuruvilla #else 1127af88ac7SKuriakose Kuruvilla 0, /* fx_eip */ 1137af88ac7SKuriakose Kuruvilla 0, /* fx_cs */ 1147af88ac7SKuriakose Kuruvilla 0, /* __fx_ign0 */ 1157af88ac7SKuriakose Kuruvilla 0, /* fx_dp */ 1167af88ac7SKuriakose Kuruvilla 0, /* fx_ds */ 1177af88ac7SKuriakose Kuruvilla 0, /* __fx_ign1 */ 1187af88ac7SKuriakose Kuruvilla #endif /* __amd64 */ 1197af88ac7SKuriakose Kuruvilla SSE_MXCSR_INIT /* fx_mxcsr */ 1207af88ac7SKuriakose Kuruvilla /* rest of structure is zero */ 1217af88ac7SKuriakose Kuruvilla }, 1227af88ac7SKuriakose Kuruvilla /* 1237af88ac7SKuriakose Kuruvilla * bit0 = 1 for XSTATE_BV to indicate that legacy fields are valid, 1247af88ac7SKuriakose Kuruvilla * and CPU should initialize XMM/YMM. 1257af88ac7SKuriakose Kuruvilla */ 1267af88ac7SKuriakose Kuruvilla 1, 1277af88ac7SKuriakose Kuruvilla {0, 0} /* These 2 bytes must be zero */ 1287af88ac7SKuriakose Kuruvilla /* rest of structure is zero */ 1297af88ac7SKuriakose Kuruvilla }; 1307af88ac7SKuriakose Kuruvilla 1317c478bd9Sstevel@tonic-gate /* 1327c478bd9Sstevel@tonic-gate * mxcsr_mask value (possibly reset in fpu_probe); used to avoid 1337c478bd9Sstevel@tonic-gate * the #gp exception caused by setting unsupported bits in the 1347c478bd9Sstevel@tonic-gate * MXCSR register 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate uint32_t sse_mxcsr_mask = SSE_MXCSR_MASK_DEFAULT; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate /* 1397c478bd9Sstevel@tonic-gate * Initial kfpu state for x87 used by fpinit() 1407c478bd9Sstevel@tonic-gate */ 1417c478bd9Sstevel@tonic-gate const struct fnsave_state x87_initial = { 1427c478bd9Sstevel@tonic-gate FPU_CW_INIT, /* f_fcw */ 1437c478bd9Sstevel@tonic-gate 0, /* __f_ign0 */ 1447c478bd9Sstevel@tonic-gate 0, /* f_fsw */ 1457c478bd9Sstevel@tonic-gate 0, /* __f_ign1 */ 1467c478bd9Sstevel@tonic-gate 0xffff, /* f_ftw */ 1477c478bd9Sstevel@tonic-gate /* rest of structure is zero */ 1487c478bd9Sstevel@tonic-gate }; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate #if defined(__amd64) 1517af88ac7SKuriakose Kuruvilla /* 1527af88ac7SKuriakose Kuruvilla * This vector is patched to xsave_ctxt() if we discover we have an 1537af88ac7SKuriakose Kuruvilla * XSAVE-capable chip in fpu_probe. 1547af88ac7SKuriakose Kuruvilla */ 1557af88ac7SKuriakose Kuruvilla void (*fpsave_ctxt)(void *) = fpxsave_ctxt; 1567c478bd9Sstevel@tonic-gate #elif defined(__i386) 1577c478bd9Sstevel@tonic-gate /* 1587af88ac7SKuriakose Kuruvilla * This vector is patched to fpxsave_ctxt() if we discover we have an 1597af88ac7SKuriakose Kuruvilla * SSE-capable chip in fpu_probe(). It is patched to xsave_ctxt 1607af88ac7SKuriakose Kuruvilla * if we discover we have an XSAVE-capable chip in fpu_probe. 1617c478bd9Sstevel@tonic-gate */ 162ae115bc7Smrj void (*fpsave_ctxt)(void *) = fpnsave_ctxt; 1637c478bd9Sstevel@tonic-gate #endif 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate static int fpe_sicode(uint_t); 1667c478bd9Sstevel@tonic-gate static int fpe_simd_sicode(uint_t); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate /* 1697c478bd9Sstevel@tonic-gate * Copy the state of parent lwp's floating point context into the new lwp. 1707c478bd9Sstevel@tonic-gate * Invoked for both fork() and lwp_create(). 1717c478bd9Sstevel@tonic-gate * 1727c478bd9Sstevel@tonic-gate * Note that we inherit -only- the control state (e.g. exception masks, 1737c478bd9Sstevel@tonic-gate * rounding, precision control, etc.); the FPU registers are otherwise 1747c478bd9Sstevel@tonic-gate * reset to their initial state. 1757c478bd9Sstevel@tonic-gate */ 1767c478bd9Sstevel@tonic-gate static void 1777c478bd9Sstevel@tonic-gate fp_new_lwp(kthread_id_t t, kthread_id_t ct) 1787c478bd9Sstevel@tonic-gate { 1797c478bd9Sstevel@tonic-gate struct fpu_ctx *fp; /* parent fpu context */ 1807c478bd9Sstevel@tonic-gate struct fpu_ctx *cfp; /* new fpu context */ 1817c478bd9Sstevel@tonic-gate struct fxsave_state *fx, *cfx; 1827af88ac7SKuriakose Kuruvilla #if defined(__i386) 1837af88ac7SKuriakose Kuruvilla struct fnsave_state *fn, *cfn; 1847af88ac7SKuriakose Kuruvilla #endif 1857af88ac7SKuriakose Kuruvilla struct xsave_state *cxs; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate ASSERT(fp_kind != FP_NO); 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate fp = &t->t_lwp->lwp_pcb.pcb_fpu; 1907c478bd9Sstevel@tonic-gate cfp = &ct->t_lwp->lwp_pcb.pcb_fpu; 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * If the parent FPU state is still in the FPU hw then save it; 1947c478bd9Sstevel@tonic-gate * conveniently, fp_save() already does this for us nicely. 1957c478bd9Sstevel@tonic-gate */ 1967c478bd9Sstevel@tonic-gate fp_save(fp); 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate cfp->fpu_flags = FPU_EN | FPU_VALID; 1997c478bd9Sstevel@tonic-gate cfp->fpu_regs.kfpu_status = 0; 2007c478bd9Sstevel@tonic-gate cfp->fpu_regs.kfpu_xstatus = 0; 2017c478bd9Sstevel@tonic-gate 2027af88ac7SKuriakose Kuruvilla switch (fp_save_mech) { 2037af88ac7SKuriakose Kuruvilla #if defined(__i386) 2047af88ac7SKuriakose Kuruvilla case FP_FNSAVE: 2057af88ac7SKuriakose Kuruvilla fn = &fp->fpu_regs.kfpu_u.kfpu_fn; 2067af88ac7SKuriakose Kuruvilla cfn = &cfp->fpu_regs.kfpu_u.kfpu_fn; 2077c478bd9Sstevel@tonic-gate bcopy(&x87_initial, cfn, sizeof (*cfn)); 2087c478bd9Sstevel@tonic-gate cfn->f_fcw = fn->f_fcw; 2097af88ac7SKuriakose Kuruvilla break; 2107c478bd9Sstevel@tonic-gate #endif 2117af88ac7SKuriakose Kuruvilla case FP_FXSAVE: 2127af88ac7SKuriakose Kuruvilla fx = &fp->fpu_regs.kfpu_u.kfpu_fx; 2137af88ac7SKuriakose Kuruvilla cfx = &cfp->fpu_regs.kfpu_u.kfpu_fx; 2147af88ac7SKuriakose Kuruvilla bcopy(&sse_initial, cfx, sizeof (*cfx)); 2157af88ac7SKuriakose Kuruvilla cfx->fx_mxcsr = fx->fx_mxcsr & ~SSE_MXCSR_EFLAGS; 2167af88ac7SKuriakose Kuruvilla cfx->fx_fcw = fx->fx_fcw; 2177af88ac7SKuriakose Kuruvilla break; 2187af88ac7SKuriakose Kuruvilla 2197af88ac7SKuriakose Kuruvilla case FP_XSAVE: 2207af88ac7SKuriakose Kuruvilla cfp->fpu_xsave_mask = fp->fpu_xsave_mask; 2217af88ac7SKuriakose Kuruvilla 2227af88ac7SKuriakose Kuruvilla fx = &fp->fpu_regs.kfpu_u.kfpu_xs.xs_fxsave; 2237af88ac7SKuriakose Kuruvilla cxs = &cfp->fpu_regs.kfpu_u.kfpu_xs; 2247af88ac7SKuriakose Kuruvilla cfx = &cxs->xs_fxsave; 2257af88ac7SKuriakose Kuruvilla 2267af88ac7SKuriakose Kuruvilla bcopy(&avx_initial, cxs, sizeof (*cxs)); 2277af88ac7SKuriakose Kuruvilla cfx->fx_mxcsr = fx->fx_mxcsr & ~SSE_MXCSR_EFLAGS; 2287af88ac7SKuriakose Kuruvilla cfx->fx_fcw = fx->fx_fcw; 2297af88ac7SKuriakose Kuruvilla cxs->xs_xstate_bv |= (get_xcr(XFEATURE_ENABLED_MASK) & 2307af88ac7SKuriakose Kuruvilla XFEATURE_FP_ALL); 2317af88ac7SKuriakose Kuruvilla break; 2327af88ac7SKuriakose Kuruvilla default: 2337af88ac7SKuriakose Kuruvilla panic("Invalid fp_save_mech"); 2347af88ac7SKuriakose Kuruvilla /*NOTREACHED*/ 2357af88ac7SKuriakose Kuruvilla } 2367af88ac7SKuriakose Kuruvilla 2377c478bd9Sstevel@tonic-gate installctx(ct, cfp, 238ae115bc7Smrj fpsave_ctxt, NULL, fp_new_lwp, fp_new_lwp, NULL, fp_free); 2397c478bd9Sstevel@tonic-gate /* 2407c478bd9Sstevel@tonic-gate * Now, when the new lwp starts running, it will take a trap 2417c478bd9Sstevel@tonic-gate * that will be handled inline in the trap table to cause 2427c478bd9Sstevel@tonic-gate * the appropriate f*rstor instruction to load the save area we 2437c478bd9Sstevel@tonic-gate * constructed above directly into the hardware. 2447c478bd9Sstevel@tonic-gate */ 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate /* 2487c478bd9Sstevel@tonic-gate * Free any state associated with floating point context. 2497c478bd9Sstevel@tonic-gate * Fp_free can be called in three cases: 2507c478bd9Sstevel@tonic-gate * 1) from reaper -> thread_free -> ctxfree -> fp_free 2517c478bd9Sstevel@tonic-gate * fp context belongs to a thread on deathrow 2527c478bd9Sstevel@tonic-gate * nothing to do, thread will never be resumed 2537c478bd9Sstevel@tonic-gate * thread calling ctxfree is reaper 2547c478bd9Sstevel@tonic-gate * 2557c478bd9Sstevel@tonic-gate * 2) from exec -> ctxfree -> fp_free 2567c478bd9Sstevel@tonic-gate * fp context belongs to the current thread 2577c478bd9Sstevel@tonic-gate * must disable fpu, thread calling ctxfree is curthread 2587c478bd9Sstevel@tonic-gate * 2597c478bd9Sstevel@tonic-gate * 3) from restorecontext -> setfpregs -> fp_free 2607c478bd9Sstevel@tonic-gate * we have a modified context in the memory (lwp->pcb_fpu) 2617c478bd9Sstevel@tonic-gate * disable fpu and release the fp context for the CPU 2627c478bd9Sstevel@tonic-gate * 2637c478bd9Sstevel@tonic-gate */ 2647c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2657c478bd9Sstevel@tonic-gate void 2667c478bd9Sstevel@tonic-gate fp_free(struct fpu_ctx *fp, int isexec) 2677c478bd9Sstevel@tonic-gate { 2687c478bd9Sstevel@tonic-gate ASSERT(fp_kind != FP_NO); 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate if (fp->fpu_flags & FPU_VALID) 2717c478bd9Sstevel@tonic-gate return; 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate kpreempt_disable(); 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * We want to do fpsave rather than fpdisable so that we can 2767c478bd9Sstevel@tonic-gate * keep the fpu_flags as FPU_VALID tracking the CR0_TS bit 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate fp->fpu_flags |= FPU_VALID; 2797c478bd9Sstevel@tonic-gate /* If for current thread disable FP to track FPU_VALID */ 2807c478bd9Sstevel@tonic-gate if (curthread->t_lwp && fp == &curthread->t_lwp->lwp_pcb.pcb_fpu) { 2817c478bd9Sstevel@tonic-gate /* Clear errors if any to prevent frstor from complaining */ 2827c478bd9Sstevel@tonic-gate (void) fperr_reset(); 2837af88ac7SKuriakose Kuruvilla if (fp_kind & __FP_SSE) 2847c478bd9Sstevel@tonic-gate (void) fpxerr_reset(); 2857c478bd9Sstevel@tonic-gate fpdisable(); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate kpreempt_enable(); 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate /* 2917c478bd9Sstevel@tonic-gate * Store the floating point state and disable the floating point unit. 2927c478bd9Sstevel@tonic-gate */ 2937c478bd9Sstevel@tonic-gate void 2947c478bd9Sstevel@tonic-gate fp_save(struct fpu_ctx *fp) 2957c478bd9Sstevel@tonic-gate { 2967c478bd9Sstevel@tonic-gate ASSERT(fp_kind != FP_NO); 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate kpreempt_disable(); 2997c478bd9Sstevel@tonic-gate if (!fp || fp->fpu_flags & FPU_VALID) { 3007c478bd9Sstevel@tonic-gate kpreempt_enable(); 3017c478bd9Sstevel@tonic-gate return; 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate ASSERT(curthread->t_lwp && fp == &curthread->t_lwp->lwp_pcb.pcb_fpu); 3047c478bd9Sstevel@tonic-gate 3057af88ac7SKuriakose Kuruvilla switch (fp_save_mech) { 3067af88ac7SKuriakose Kuruvilla #if defined(__i386) 3077af88ac7SKuriakose Kuruvilla case FP_FNSAVE: 3087c478bd9Sstevel@tonic-gate fpsave(&fp->fpu_regs.kfpu_u.kfpu_fn); 3097c478bd9Sstevel@tonic-gate break; 3107c478bd9Sstevel@tonic-gate #endif 3117af88ac7SKuriakose Kuruvilla case FP_FXSAVE: 3127af88ac7SKuriakose Kuruvilla fpxsave(&fp->fpu_regs.kfpu_u.kfpu_fx); 3137af88ac7SKuriakose Kuruvilla break; 3147af88ac7SKuriakose Kuruvilla 3157af88ac7SKuriakose Kuruvilla case FP_XSAVE: 3167af88ac7SKuriakose Kuruvilla xsave(&fp->fpu_regs.kfpu_u.kfpu_xs, fp->fpu_xsave_mask); 3177af88ac7SKuriakose Kuruvilla break; 3187af88ac7SKuriakose Kuruvilla default: 3197af88ac7SKuriakose Kuruvilla panic("Invalid fp_save_mech"); 3207af88ac7SKuriakose Kuruvilla /*NOTREACHED*/ 3217af88ac7SKuriakose Kuruvilla } 3227af88ac7SKuriakose Kuruvilla 3237c478bd9Sstevel@tonic-gate fp->fpu_flags |= FPU_VALID; 3247c478bd9Sstevel@tonic-gate kpreempt_enable(); 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate /* 3287c478bd9Sstevel@tonic-gate * Restore the FPU context for the thread: 3297c478bd9Sstevel@tonic-gate * The possibilities are: 3307c478bd9Sstevel@tonic-gate * 1. No active FPU context: Load the new context into the FPU hw 3317c478bd9Sstevel@tonic-gate * and enable the FPU. 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate void 3347c478bd9Sstevel@tonic-gate fp_restore(struct fpu_ctx *fp) 3357c478bd9Sstevel@tonic-gate { 3367af88ac7SKuriakose Kuruvilla switch (fp_save_mech) { 3377af88ac7SKuriakose Kuruvilla #if defined(__i386) 3387af88ac7SKuriakose Kuruvilla case FP_FNSAVE: 3397c478bd9Sstevel@tonic-gate fprestore(&fp->fpu_regs.kfpu_u.kfpu_fn); 3407af88ac7SKuriakose Kuruvilla break; 3417c478bd9Sstevel@tonic-gate #endif 3427af88ac7SKuriakose Kuruvilla case FP_FXSAVE: 3437af88ac7SKuriakose Kuruvilla fpxrestore(&fp->fpu_regs.kfpu_u.kfpu_fx); 3447af88ac7SKuriakose Kuruvilla break; 3457af88ac7SKuriakose Kuruvilla 3467af88ac7SKuriakose Kuruvilla case FP_XSAVE: 3477af88ac7SKuriakose Kuruvilla xrestore(&fp->fpu_regs.kfpu_u.kfpu_xs, fp->fpu_xsave_mask); 3487af88ac7SKuriakose Kuruvilla break; 3497af88ac7SKuriakose Kuruvilla default: 3507af88ac7SKuriakose Kuruvilla panic("Invalid fp_save_mech"); 3517af88ac7SKuriakose Kuruvilla /*NOTREACHED*/ 3527af88ac7SKuriakose Kuruvilla } 3537af88ac7SKuriakose Kuruvilla 3547c478bd9Sstevel@tonic-gate fp->fpu_flags &= ~FPU_VALID; 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* 3597c478bd9Sstevel@tonic-gate * Seeds the initial state for the current thread. The possibilities are: 3607c478bd9Sstevel@tonic-gate * 1. Another process has modified the FPU state before we have done any 3617c478bd9Sstevel@tonic-gate * initialization: Load the FPU state from the LWP state. 3627c478bd9Sstevel@tonic-gate * 2. The FPU state has not been externally modified: Load a clean state. 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate static void 3657c478bd9Sstevel@tonic-gate fp_seed(void) 3667c478bd9Sstevel@tonic-gate { 3677c478bd9Sstevel@tonic-gate struct fpu_ctx *fp = &ttolwp(curthread)->lwp_pcb.pcb_fpu; 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate ASSERT(curthread->t_preempt >= 1); 3707c478bd9Sstevel@tonic-gate ASSERT((fp->fpu_flags & FPU_EN) == 0); 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* 3737c478bd9Sstevel@tonic-gate * Always initialize a new context and initialize the hardware. 3747c478bd9Sstevel@tonic-gate */ 3757af88ac7SKuriakose Kuruvilla if (fp_save_mech == FP_XSAVE) { 3767af88ac7SKuriakose Kuruvilla fp->fpu_xsave_mask = get_xcr(XFEATURE_ENABLED_MASK) & 3777af88ac7SKuriakose Kuruvilla XFEATURE_FP_ALL; 3787af88ac7SKuriakose Kuruvilla } 3797af88ac7SKuriakose Kuruvilla 3807c478bd9Sstevel@tonic-gate installctx(curthread, fp, 381ae115bc7Smrj fpsave_ctxt, NULL, fp_new_lwp, fp_new_lwp, NULL, fp_free); 3827c478bd9Sstevel@tonic-gate fpinit(); 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate /* 3857c478bd9Sstevel@tonic-gate * If FPU_VALID is set, it means someone has modified registers via 3867c478bd9Sstevel@tonic-gate * /proc. In this case, restore the current lwp's state. 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate if (fp->fpu_flags & FPU_VALID) 3897c478bd9Sstevel@tonic-gate fp_restore(fp); 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate ASSERT((fp->fpu_flags & FPU_VALID) == 0); 3927c478bd9Sstevel@tonic-gate fp->fpu_flags = FPU_EN; 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate /* 3967c478bd9Sstevel@tonic-gate * This routine is called from trap() when User thread takes No Extension 3977c478bd9Sstevel@tonic-gate * Fault. The possiblities are: 3987c478bd9Sstevel@tonic-gate * 1. User thread has executed a FP instruction for the first time. 3997c478bd9Sstevel@tonic-gate * Save current FPU context if any. Initialize FPU, setup FPU 4007c478bd9Sstevel@tonic-gate * context for the thread and enable FP hw. 4017c478bd9Sstevel@tonic-gate * 2. Thread's pcb has a valid FPU state: Restore the FPU state and 4027c478bd9Sstevel@tonic-gate * enable FP hw. 4037c478bd9Sstevel@tonic-gate * 4047c478bd9Sstevel@tonic-gate * Note that case #2 is inlined in the trap table. 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate int 4077c478bd9Sstevel@tonic-gate fpnoextflt(struct regs *rp) 4087c478bd9Sstevel@tonic-gate { 4097c478bd9Sstevel@tonic-gate struct fpu_ctx *fp = &ttolwp(curthread)->lwp_pcb.pcb_fpu; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate #if !defined(__lint) 4127c478bd9Sstevel@tonic-gate ASSERT(sizeof (struct fxsave_state) == 512 && 4137c478bd9Sstevel@tonic-gate sizeof (struct fnsave_state) == 108); 4147c478bd9Sstevel@tonic-gate ASSERT((offsetof(struct fxsave_state, fx_xmm[0]) & 0xf) == 0); 4157af88ac7SKuriakose Kuruvilla 4167af88ac7SKuriakose Kuruvilla ASSERT(sizeof (struct xsave_state) >= AVX_XSAVE_SIZE); 4177af88ac7SKuriakose Kuruvilla 4187c478bd9Sstevel@tonic-gate #if defined(__i386) 419*bc0e9132SGordon Ross ASSERT(sizeof (struct _fpu) == sizeof (struct __old_fpu)); 4207c478bd9Sstevel@tonic-gate #endif /* __i386 */ 4217c478bd9Sstevel@tonic-gate #endif /* !__lint */ 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate /* 4247c478bd9Sstevel@tonic-gate * save area MUST be 16-byte aligned, else will page fault 4257c478bd9Sstevel@tonic-gate */ 4267c478bd9Sstevel@tonic-gate ASSERT(((uintptr_t)(&fp->fpu_regs.kfpu_u.kfpu_fx) & 0xf) == 0); 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate kpreempt_disable(); 4297c478bd9Sstevel@tonic-gate /* 4307c478bd9Sstevel@tonic-gate * Now we can enable the interrupts. 4317c478bd9Sstevel@tonic-gate * (NOTE: fp-no-coprocessor comes thru interrupt gate) 4327c478bd9Sstevel@tonic-gate */ 4337c478bd9Sstevel@tonic-gate sti(); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate if (!fpu_exists) { /* check for FPU hw exists */ 4367c478bd9Sstevel@tonic-gate if (fp_kind == FP_NO) { 4377c478bd9Sstevel@tonic-gate uint32_t inst; 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate /* 4407c478bd9Sstevel@tonic-gate * When the system has no floating point support, 4417c478bd9Sstevel@tonic-gate * i.e. no FP hardware and no emulator, skip the 4427c478bd9Sstevel@tonic-gate * two kinds of FP instruction that occur in 4437c478bd9Sstevel@tonic-gate * fpstart. Allows processes that do no real FP 4447c478bd9Sstevel@tonic-gate * to run normally. 4457c478bd9Sstevel@tonic-gate */ 4467c478bd9Sstevel@tonic-gate if (fuword32((void *)rp->r_pc, &inst) != -1 && 4477c478bd9Sstevel@tonic-gate ((inst & 0xFFFF) == 0x7dd9 || 4487c478bd9Sstevel@tonic-gate (inst & 0xFFFF) == 0x6dd9)) { 4497c478bd9Sstevel@tonic-gate rp->r_pc += 3; 4507c478bd9Sstevel@tonic-gate kpreempt_enable(); 4517c478bd9Sstevel@tonic-gate return (0); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate /* 4567c478bd9Sstevel@tonic-gate * If we have neither a processor extension nor 4577c478bd9Sstevel@tonic-gate * an emulator, kill the process OR panic the kernel. 4587c478bd9Sstevel@tonic-gate */ 4597c478bd9Sstevel@tonic-gate kpreempt_enable(); 4607c478bd9Sstevel@tonic-gate return (1); /* error */ 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate 463843e1988Sjohnlev #if !defined(__xpv) /* XXPV Is this ifdef needed now? */ 4647c478bd9Sstevel@tonic-gate /* 4657c478bd9Sstevel@tonic-gate * A paranoid cross-check: for the SSE case, ensure that %cr4 is 4667c478bd9Sstevel@tonic-gate * configured to enable fully fledged (%xmm) fxsave/fxrestor on 4677c478bd9Sstevel@tonic-gate * this CPU. For the non-SSE case, ensure that it isn't. 4687c478bd9Sstevel@tonic-gate */ 4697af88ac7SKuriakose Kuruvilla ASSERT(((fp_kind & __FP_SSE) && 4707af88ac7SKuriakose Kuruvilla (getcr4() & CR4_OSFXSR) == CR4_OSFXSR) || 4717af88ac7SKuriakose Kuruvilla (!(fp_kind & __FP_SSE) && 4727c478bd9Sstevel@tonic-gate (getcr4() & (CR4_OSXMMEXCPT|CR4_OSFXSR)) == 0)); 473843e1988Sjohnlev #endif 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate if (fp->fpu_flags & FPU_EN) { 4767c478bd9Sstevel@tonic-gate /* case 2 */ 4777c478bd9Sstevel@tonic-gate fp_restore(fp); 4787c478bd9Sstevel@tonic-gate } else { 4797c478bd9Sstevel@tonic-gate /* case 1 */ 4807c478bd9Sstevel@tonic-gate fp_seed(); 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate kpreempt_enable(); 4837c478bd9Sstevel@tonic-gate return (0); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate /* 4887c478bd9Sstevel@tonic-gate * Handle a processor extension overrun fault 4897c478bd9Sstevel@tonic-gate * Returns non zero for error. 490ae115bc7Smrj * 491ae115bc7Smrj * XXX Shouldn't this just be abolished given that we're not supporting 492ae115bc7Smrj * anything prior to Pentium? 4937c478bd9Sstevel@tonic-gate */ 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4967c478bd9Sstevel@tonic-gate int 4977c478bd9Sstevel@tonic-gate fpextovrflt(struct regs *rp) 4987c478bd9Sstevel@tonic-gate { 499843e1988Sjohnlev #if !defined(__xpv) /* XXPV Do we need this ifdef either */ 5007c478bd9Sstevel@tonic-gate ulong_t cur_cr0; 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate ASSERT(fp_kind != FP_NO); 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate cur_cr0 = getcr0(); 5057c478bd9Sstevel@tonic-gate fpinit(); /* initialize the FPU hardware */ 5067c478bd9Sstevel@tonic-gate setcr0(cur_cr0); 507843e1988Sjohnlev #endif 5087c478bd9Sstevel@tonic-gate sti(); 5097c478bd9Sstevel@tonic-gate return (1); /* error, send SIGSEGV signal to the thread */ 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate /* 5137c478bd9Sstevel@tonic-gate * Handle a processor extension error fault 5147c478bd9Sstevel@tonic-gate * Returns non zero for error. 5157c478bd9Sstevel@tonic-gate */ 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5187c478bd9Sstevel@tonic-gate int 5197c478bd9Sstevel@tonic-gate fpexterrflt(struct regs *rp) 5207c478bd9Sstevel@tonic-gate { 521eae0da43Ssethg uint32_t fpcw, fpsw; 5227c478bd9Sstevel@tonic-gate fpu_ctx_t *fp = &ttolwp(curthread)->lwp_pcb.pcb_fpu; 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate ASSERT(fp_kind != FP_NO); 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate /* 5277c478bd9Sstevel@tonic-gate * Now we can enable the interrupts. 5287c478bd9Sstevel@tonic-gate * (NOTE: x87 fp exceptions come thru interrupt gate) 5297c478bd9Sstevel@tonic-gate */ 5307c478bd9Sstevel@tonic-gate sti(); 5317c478bd9Sstevel@tonic-gate 532eae0da43Ssethg if (!fpu_exists) 533eae0da43Ssethg return (FPE_FLTINV); 5347c478bd9Sstevel@tonic-gate 535eae0da43Ssethg /* 536eae0da43Ssethg * Do an unconditional save of the FP state. If it's dirty (TS=0), 537eae0da43Ssethg * it'll be saved into the fpu context area passed in (that of the 538eae0da43Ssethg * current thread). If it's not dirty (it may not be, due to 539eae0da43Ssethg * an intervening save due to a context switch between the sti(), 540eae0da43Ssethg * above and here, then it's safe to just use the stored values in 541eae0da43Ssethg * the context save area to determine the cause of the fault. 542eae0da43Ssethg */ 5437c478bd9Sstevel@tonic-gate fp_save(fp); 544eae0da43Ssethg 5457c478bd9Sstevel@tonic-gate /* clear exception flags in saved state, as if by fnclex */ 5467af88ac7SKuriakose Kuruvilla switch (fp_save_mech) { 5477af88ac7SKuriakose Kuruvilla #if defined(__i386) 5487af88ac7SKuriakose Kuruvilla case FP_FNSAVE: 549eae0da43Ssethg fpsw = fp->fpu_regs.kfpu_u.kfpu_fn.f_fsw; 550eae0da43Ssethg fpcw = fp->fpu_regs.kfpu_u.kfpu_fn.f_fcw; 5517c478bd9Sstevel@tonic-gate fp->fpu_regs.kfpu_u.kfpu_fn.f_fsw &= ~FPS_SW_EFLAGS; 5527c478bd9Sstevel@tonic-gate break; 5537c478bd9Sstevel@tonic-gate #endif 554eae0da43Ssethg 5557af88ac7SKuriakose Kuruvilla case FP_FXSAVE: 5567af88ac7SKuriakose Kuruvilla fpsw = fp->fpu_regs.kfpu_u.kfpu_fx.fx_fsw; 5577af88ac7SKuriakose Kuruvilla fpcw = fp->fpu_regs.kfpu_u.kfpu_fx.fx_fcw; 5587af88ac7SKuriakose Kuruvilla fp->fpu_regs.kfpu_u.kfpu_fx.fx_fsw &= ~FPS_SW_EFLAGS; 5597af88ac7SKuriakose Kuruvilla break; 5607af88ac7SKuriakose Kuruvilla 5617af88ac7SKuriakose Kuruvilla case FP_XSAVE: 5627af88ac7SKuriakose Kuruvilla fpsw = fp->fpu_regs.kfpu_u.kfpu_xs.xs_fxsave.fx_fsw; 5637af88ac7SKuriakose Kuruvilla fpcw = fp->fpu_regs.kfpu_u.kfpu_xs.xs_fxsave.fx_fcw; 5647af88ac7SKuriakose Kuruvilla fp->fpu_regs.kfpu_u.kfpu_xs.xs_fxsave.fx_fsw &= ~FPS_SW_EFLAGS; 5657af88ac7SKuriakose Kuruvilla /* 5667af88ac7SKuriakose Kuruvilla * Always set LEGACY_FP as it may have been cleared by XSAVE 5677af88ac7SKuriakose Kuruvilla * instruction 5687af88ac7SKuriakose Kuruvilla */ 5697af88ac7SKuriakose Kuruvilla fp->fpu_regs.kfpu_u.kfpu_xs.xs_xstate_bv |= XFEATURE_LEGACY_FP; 5707af88ac7SKuriakose Kuruvilla break; 5717af88ac7SKuriakose Kuruvilla default: 5727af88ac7SKuriakose Kuruvilla panic("Invalid fp_save_mech"); 5737af88ac7SKuriakose Kuruvilla /*NOTREACHED*/ 5747af88ac7SKuriakose Kuruvilla } 5757af88ac7SKuriakose Kuruvilla 576eae0da43Ssethg fp->fpu_regs.kfpu_status = fpsw; 577eae0da43Ssethg 578eae0da43Ssethg if ((fpsw & FPS_ES) == 0) 579eae0da43Ssethg return (0); /* No exception */ 580eae0da43Ssethg 5817c478bd9Sstevel@tonic-gate /* 5827c478bd9Sstevel@tonic-gate * "and" the exception flags with the complement of the mask 5837c478bd9Sstevel@tonic-gate * bits to determine which exception occurred 5847c478bd9Sstevel@tonic-gate */ 585eae0da43Ssethg return (fpe_sicode(fpsw & ~fpcw & 0x3f)); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate /* 5897c478bd9Sstevel@tonic-gate * Handle an SSE/SSE2 precise exception. 5907c478bd9Sstevel@tonic-gate * Returns a non-zero sicode for error. 5917c478bd9Sstevel@tonic-gate */ 5927c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5937c478bd9Sstevel@tonic-gate int 5947c478bd9Sstevel@tonic-gate fpsimderrflt(struct regs *rp) 5957c478bd9Sstevel@tonic-gate { 5967c478bd9Sstevel@tonic-gate uint32_t mxcsr, xmask; 5977c478bd9Sstevel@tonic-gate fpu_ctx_t *fp = &ttolwp(curthread)->lwp_pcb.pcb_fpu; 5987c478bd9Sstevel@tonic-gate 5997af88ac7SKuriakose Kuruvilla ASSERT(fp_kind & __FP_SSE); 6007c478bd9Sstevel@tonic-gate 601eae0da43Ssethg /* 602eae0da43Ssethg * NOTE: Interrupts are disabled during execution of this 603eae0da43Ssethg * function. They are enabled by the caller in trap.c. 604eae0da43Ssethg */ 605eae0da43Ssethg 606eae0da43Ssethg /* 607eae0da43Ssethg * The only way we could have gotten here if there is no FP unit 608eae0da43Ssethg * is via a user executing an INT $19 instruction, so there is 609eae0da43Ssethg * no fault in that case. 610eae0da43Ssethg */ 611eae0da43Ssethg if (!fpu_exists) 612eae0da43Ssethg return (0); 613eae0da43Ssethg 614eae0da43Ssethg /* 615eae0da43Ssethg * Do an unconditional save of the FP state. If it's dirty (TS=0), 616eae0da43Ssethg * it'll be saved into the fpu context area passed in (that of the 617eae0da43Ssethg * current thread). If it's not dirty, then it's safe to just use 618eae0da43Ssethg * the stored values in the context save area to determine the 619eae0da43Ssethg * cause of the fault. 620eae0da43Ssethg */ 6217c478bd9Sstevel@tonic-gate fp_save(fp); /* save the FPU state */ 622eae0da43Ssethg 623eae0da43Ssethg mxcsr = fp->fpu_regs.kfpu_u.kfpu_fx.fx_mxcsr; 624eae0da43Ssethg 6257c478bd9Sstevel@tonic-gate fp->fpu_regs.kfpu_status = fp->fpu_regs.kfpu_u.kfpu_fx.fx_fsw; 626eae0da43Ssethg 6277c478bd9Sstevel@tonic-gate fp->fpu_regs.kfpu_xstatus = mxcsr; 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate /* 6307c478bd9Sstevel@tonic-gate * compute the mask that determines which conditions can cause 6317c478bd9Sstevel@tonic-gate * a #xm exception, and use this to clean the status bits so that 6327c478bd9Sstevel@tonic-gate * we can identify the true cause of this one. 6337c478bd9Sstevel@tonic-gate */ 6347c478bd9Sstevel@tonic-gate xmask = (mxcsr >> 7) & SSE_MXCSR_EFLAGS; 6357c478bd9Sstevel@tonic-gate return (fpe_simd_sicode((mxcsr & SSE_MXCSR_EFLAGS) & ~xmask)); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate /* 6397c478bd9Sstevel@tonic-gate * In the unlikely event that someone is relying on this subcode being 6407c478bd9Sstevel@tonic-gate * FPE_FLTILL for denormalize exceptions, it can always be patched back 6417c478bd9Sstevel@tonic-gate * again to restore old behaviour. 6427c478bd9Sstevel@tonic-gate */ 6437c478bd9Sstevel@tonic-gate int fpe_fltden = FPE_FLTDEN; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate /* 6467c478bd9Sstevel@tonic-gate * Map from the FPU status word to the FP exception si_code. 6477c478bd9Sstevel@tonic-gate */ 6487c478bd9Sstevel@tonic-gate static int 6497c478bd9Sstevel@tonic-gate fpe_sicode(uint_t sw) 6507c478bd9Sstevel@tonic-gate { 6517c478bd9Sstevel@tonic-gate if (sw & FPS_IE) 6527c478bd9Sstevel@tonic-gate return (FPE_FLTINV); 6537c478bd9Sstevel@tonic-gate if (sw & FPS_ZE) 6547c478bd9Sstevel@tonic-gate return (FPE_FLTDIV); 6557c478bd9Sstevel@tonic-gate if (sw & FPS_DE) 6567c478bd9Sstevel@tonic-gate return (fpe_fltden); 6577c478bd9Sstevel@tonic-gate if (sw & FPS_OE) 6587c478bd9Sstevel@tonic-gate return (FPE_FLTOVF); 6597c478bd9Sstevel@tonic-gate if (sw & FPS_UE) 6607c478bd9Sstevel@tonic-gate return (FPE_FLTUND); 6617c478bd9Sstevel@tonic-gate if (sw & FPS_PE) 6627c478bd9Sstevel@tonic-gate return (FPE_FLTRES); 6637c478bd9Sstevel@tonic-gate return (FPE_FLTINV); /* default si_code for other exceptions */ 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate /* 6677c478bd9Sstevel@tonic-gate * Map from the SSE status word to the FP exception si_code. 6687c478bd9Sstevel@tonic-gate */ 6697c478bd9Sstevel@tonic-gate static int 6707c478bd9Sstevel@tonic-gate fpe_simd_sicode(uint_t sw) 6717c478bd9Sstevel@tonic-gate { 6727c478bd9Sstevel@tonic-gate if (sw & SSE_IE) 6737c478bd9Sstevel@tonic-gate return (FPE_FLTINV); 6747c478bd9Sstevel@tonic-gate if (sw & SSE_ZE) 6757c478bd9Sstevel@tonic-gate return (FPE_FLTDIV); 6767c478bd9Sstevel@tonic-gate if (sw & SSE_DE) 6777c478bd9Sstevel@tonic-gate return (FPE_FLTDEN); 6787c478bd9Sstevel@tonic-gate if (sw & SSE_OE) 6797c478bd9Sstevel@tonic-gate return (FPE_FLTOVF); 6807c478bd9Sstevel@tonic-gate if (sw & SSE_UE) 6817c478bd9Sstevel@tonic-gate return (FPE_FLTUND); 6827c478bd9Sstevel@tonic-gate if (sw & SSE_PE) 6837c478bd9Sstevel@tonic-gate return (FPE_FLTRES); 6847c478bd9Sstevel@tonic-gate return (FPE_FLTINV); /* default si_code for other exceptions */ 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 6887c478bd9Sstevel@tonic-gate * This routine is invoked as part of libc's __fpstart implementation 6897c478bd9Sstevel@tonic-gate * via sysi86(2). 6907c478bd9Sstevel@tonic-gate * 6917c478bd9Sstevel@tonic-gate * It may be called -before- any context has been assigned in which case 6927c478bd9Sstevel@tonic-gate * we try and avoid touching the hardware. Or it may be invoked well 6937c478bd9Sstevel@tonic-gate * after the context has been assigned and fiddled with, in which case 6947c478bd9Sstevel@tonic-gate * just tweak it directly. 6957c478bd9Sstevel@tonic-gate */ 6967c478bd9Sstevel@tonic-gate void 6977c478bd9Sstevel@tonic-gate fpsetcw(uint16_t fcw, uint32_t mxcsr) 6987c478bd9Sstevel@tonic-gate { 6997c478bd9Sstevel@tonic-gate struct fpu_ctx *fp = &curthread->t_lwp->lwp_pcb.pcb_fpu; 7007c478bd9Sstevel@tonic-gate struct fxsave_state *fx; 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate if (!fpu_exists || fp_kind == FP_NO) 7037c478bd9Sstevel@tonic-gate return; 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate if ((fp->fpu_flags & FPU_EN) == 0) { 7067c478bd9Sstevel@tonic-gate if (fcw == FPU_CW_INIT && mxcsr == SSE_MXCSR_INIT) { 7077c478bd9Sstevel@tonic-gate /* 7087c478bd9Sstevel@tonic-gate * Common case. Floating point unit not yet 7097c478bd9Sstevel@tonic-gate * enabled, and kernel already intends to initialize 7107c478bd9Sstevel@tonic-gate * the hardware the way the caller wants. 7117c478bd9Sstevel@tonic-gate */ 7127c478bd9Sstevel@tonic-gate return; 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate /* 7157c478bd9Sstevel@tonic-gate * Hmm. Userland wants a different default. 7167c478bd9Sstevel@tonic-gate * Do a fake "first trap" to establish the context, then 7177c478bd9Sstevel@tonic-gate * handle as if we already had a context before we came in. 7187c478bd9Sstevel@tonic-gate */ 7197c478bd9Sstevel@tonic-gate kpreempt_disable(); 7207c478bd9Sstevel@tonic-gate fp_seed(); 7217c478bd9Sstevel@tonic-gate kpreempt_enable(); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate /* 7257c478bd9Sstevel@tonic-gate * Ensure that the current hardware state is flushed back to the 7267c478bd9Sstevel@tonic-gate * pcb, then modify that copy. Next use of the fp will 7277c478bd9Sstevel@tonic-gate * restore the context. 7287c478bd9Sstevel@tonic-gate */ 7297c478bd9Sstevel@tonic-gate fp_save(fp); 7307c478bd9Sstevel@tonic-gate 7317af88ac7SKuriakose Kuruvilla switch (fp_save_mech) { 7327af88ac7SKuriakose Kuruvilla #if defined(__i386) 7337af88ac7SKuriakose Kuruvilla case FP_FNSAVE: 7347c478bd9Sstevel@tonic-gate fp->fpu_regs.kfpu_u.kfpu_fn.f_fcw = fcw; 7357c478bd9Sstevel@tonic-gate break; 7367c478bd9Sstevel@tonic-gate #endif 7377af88ac7SKuriakose Kuruvilla case FP_FXSAVE: 7387af88ac7SKuriakose Kuruvilla fx = &fp->fpu_regs.kfpu_u.kfpu_fx; 7397af88ac7SKuriakose Kuruvilla fx->fx_fcw = fcw; 7407af88ac7SKuriakose Kuruvilla fx->fx_mxcsr = sse_mxcsr_mask & mxcsr; 7417af88ac7SKuriakose Kuruvilla break; 7427af88ac7SKuriakose Kuruvilla 7437af88ac7SKuriakose Kuruvilla case FP_XSAVE: 7447af88ac7SKuriakose Kuruvilla fx = &fp->fpu_regs.kfpu_u.kfpu_xs.xs_fxsave; 7457af88ac7SKuriakose Kuruvilla fx->fx_fcw = fcw; 7467af88ac7SKuriakose Kuruvilla fx->fx_mxcsr = sse_mxcsr_mask & mxcsr; 7477af88ac7SKuriakose Kuruvilla /* 7487af88ac7SKuriakose Kuruvilla * Always set LEGACY_FP as it may have been cleared by XSAVE 7497af88ac7SKuriakose Kuruvilla * instruction 7507af88ac7SKuriakose Kuruvilla */ 7517af88ac7SKuriakose Kuruvilla fp->fpu_regs.kfpu_u.kfpu_xs.xs_xstate_bv |= XFEATURE_LEGACY_FP; 7527af88ac7SKuriakose Kuruvilla break; 7537af88ac7SKuriakose Kuruvilla default: 7547af88ac7SKuriakose Kuruvilla panic("Invalid fp_save_mech"); 7557af88ac7SKuriakose Kuruvilla /*NOTREACHED*/ 7567af88ac7SKuriakose Kuruvilla } 7577c478bd9Sstevel@tonic-gate } 758