15b81b6b3SRodney W. Grimes /*- 25b81b6b3SRodney W. Grimes * Copyright (c) 1990 William Jolitz. 35b81b6b3SRodney W. Grimes * Copyright (c) 1991 The Regents of the University of California. 45b81b6b3SRodney W. Grimes * All rights reserved. 55b81b6b3SRodney W. Grimes * 65b81b6b3SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 75b81b6b3SRodney W. Grimes * modification, are permitted provided that the following conditions 85b81b6b3SRodney W. Grimes * are met: 95b81b6b3SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 105b81b6b3SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 115b81b6b3SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 125b81b6b3SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 135b81b6b3SRodney W. Grimes * documentation and/or other materials provided with the distribution. 145b81b6b3SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 155b81b6b3SRodney W. Grimes * may be used to endorse or promote products derived from this software 165b81b6b3SRodney W. Grimes * without specific prior written permission. 175b81b6b3SRodney W. Grimes * 185b81b6b3SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 195b81b6b3SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 205b81b6b3SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 215b81b6b3SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 225b81b6b3SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 235b81b6b3SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 245b81b6b3SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 255b81b6b3SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 265b81b6b3SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 275b81b6b3SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 285b81b6b3SRodney W. Grimes * SUCH DAMAGE. 295b81b6b3SRodney W. Grimes * 3021616ec3SPeter Wemm * from: @(#)npx.c 7.2 (Berkeley) 5/12/91 315b81b6b3SRodney W. Grimes */ 325b81b6b3SRodney W. Grimes 3356ae44c5SDavid E. O'Brien #include <sys/cdefs.h> 3456ae44c5SDavid E. O'Brien __FBSDID("$FreeBSD$"); 3556ae44c5SDavid E. O'Brien 36f540b106SGarrett Wollman #include <sys/param.h> 37f540b106SGarrett Wollman #include <sys/systm.h> 386182fdbdSPeter Wemm #include <sys/bus.h> 393a34a5c3SPoul-Henning Kamp #include <sys/kernel.h> 40fb919e4dSMark Murray #include <sys/lock.h> 41cd59d49dSBruce Evans #include <sys/malloc.h> 426182fdbdSPeter Wemm #include <sys/module.h> 43c1ef8aacSJake Burkholder #include <sys/mutex.h> 44fb919e4dSMark Murray #include <sys/mutex.h> 45fb919e4dSMark Murray #include <sys/proc.h> 46fb919e4dSMark Murray #include <sys/sysctl.h> 476182fdbdSPeter Wemm #include <machine/bus.h> 486182fdbdSPeter Wemm #include <sys/rman.h> 49663f1485SBruce Evans #include <sys/signalvar.h> 502f86936aSGarrett Wollman 517f47cf2fSBruce Evans #include <machine/cputypes.h> 527f47cf2fSBruce Evans #include <machine/frame.h> 530d2a2989SPeter Wemm #include <machine/intr_machdep.h> 54c673fe98SBruce Evans #include <machine/md_var.h> 555400ed3bSPeter Wemm #include <machine/pcb.h> 567f47cf2fSBruce Evans #include <machine/psl.h> 576182fdbdSPeter Wemm #include <machine/resource.h> 58f540b106SGarrett Wollman #include <machine/specialreg.h> 597f47cf2fSBruce Evans #include <machine/segments.h> 6030abe507SJonathan Mini #include <machine/ucontext.h> 612f86936aSGarrett Wollman 625b81b6b3SRodney W. Grimes /* 63bf2f09eeSPeter Wemm * Floating point support. 645b81b6b3SRodney W. Grimes */ 655b81b6b3SRodney W. Grimes 66a5f50ef9SJoerg Wunsch #if defined(__GNUCLIKE_ASM) && !defined(lint) 675b81b6b3SRodney W. Grimes 6817275403SJung-uk Kim #define fldcw(cw) __asm __volatile("fldcw %0" : : "m" (cw)) 6930402401SJung-uk Kim #define fnclex() __asm __volatile("fnclex") 7030402401SJung-uk Kim #define fninit() __asm __volatile("fninit") 711d37f051SBruce Evans #define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr))) 722e50fa36SJung-uk Kim #define fnstsw(addr) __asm __volatile("fnstsw %0" : "=am" (*(addr))) 7330402401SJung-uk Kim #define fxrstor(addr) __asm __volatile("fxrstor %0" : : "m" (*(addr))) 749d146ac5SPeter Wemm #define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr))) 7507c86dcfSJung-uk Kim #define ldmxcsr(csr) __asm __volatile("ldmxcsr %0" : : "m" (csr)) 765b81b6b3SRodney W. Grimes 7794818d19SKonstantin Belousov static __inline void 7894818d19SKonstantin Belousov xrstor(char *addr, uint64_t mask) 7994818d19SKonstantin Belousov { 8094818d19SKonstantin Belousov uint32_t low, hi; 8194818d19SKonstantin Belousov 8294818d19SKonstantin Belousov low = mask; 8394818d19SKonstantin Belousov hi = mask >> 32; 847574a595SJohn Baldwin __asm __volatile("xrstor %0" : : "m" (*addr), "a" (low), "d" (hi)); 8594818d19SKonstantin Belousov } 8694818d19SKonstantin Belousov 8794818d19SKonstantin Belousov static __inline void 8894818d19SKonstantin Belousov xsave(char *addr, uint64_t mask) 8994818d19SKonstantin Belousov { 9094818d19SKonstantin Belousov uint32_t low, hi; 9194818d19SKonstantin Belousov 9294818d19SKonstantin Belousov low = mask; 9394818d19SKonstantin Belousov hi = mask >> 32; 947574a595SJohn Baldwin __asm __volatile("xsave %0" : "=m" (*addr) : "a" (low), "d" (hi) : 957574a595SJohn Baldwin "memory"); 9694818d19SKonstantin Belousov } 9794818d19SKonstantin Belousov 98cf4e1c46SPeter Wemm #else /* !(__GNUCLIKE_ASM && !lint) */ 995b81b6b3SRodney W. Grimes 10017275403SJung-uk Kim void fldcw(u_short cw); 10189c9a483SAlfred Perlstein void fnclex(void); 10289c9a483SAlfred Perlstein void fninit(void); 10389c9a483SAlfred Perlstein void fnstcw(caddr_t addr); 10489c9a483SAlfred Perlstein void fnstsw(caddr_t addr); 10589c9a483SAlfred Perlstein void fxsave(caddr_t addr); 10689c9a483SAlfred Perlstein void fxrstor(caddr_t addr); 10707c86dcfSJung-uk Kim void ldmxcsr(u_int csr); 10894818d19SKonstantin Belousov void xrstor(char *addr, uint64_t mask); 10994818d19SKonstantin Belousov void xsave(char *addr, uint64_t mask); 1105b81b6b3SRodney W. Grimes 111cf4e1c46SPeter Wemm #endif /* __GNUCLIKE_ASM && !lint */ 1125b81b6b3SRodney W. Grimes 113d706ec29SJohn Baldwin #define start_emulating() load_cr0(rcr0() | CR0_TS) 114d706ec29SJohn Baldwin #define stop_emulating() clts() 115d706ec29SJohn Baldwin 1166cf9a08dSKonstantin Belousov #define GET_FPU_CW(thread) ((thread)->td_pcb->pcb_save->sv_env.en_cw) 1176cf9a08dSKonstantin Belousov #define GET_FPU_SW(thread) ((thread)->td_pcb->pcb_save->sv_env.en_sw) 1189d146ac5SPeter Wemm 1198c6f8f3dSKonstantin Belousov CTASSERT(sizeof(struct savefpu) == 512); 1208c6f8f3dSKonstantin Belousov CTASSERT(sizeof(struct xstate_hdr) == 64); 1218c6f8f3dSKonstantin Belousov CTASSERT(sizeof(struct savefpu_ymm) == 832); 1228c6f8f3dSKonstantin Belousov 1238c6f8f3dSKonstantin Belousov /* 1248c6f8f3dSKonstantin Belousov * This requirement is to make it easier for asm code to calculate 1258c6f8f3dSKonstantin Belousov * offset of the fpu save area from the pcb address. FPU save area 126b74a2290SKonstantin Belousov * must be 64-byte aligned. 1278c6f8f3dSKonstantin Belousov */ 1288c6f8f3dSKonstantin Belousov CTASSERT(sizeof(struct pcb) % XSAVE_AREA_ALIGN == 0); 1295b81b6b3SRodney W. Grimes 1302652af56SColin Percival static void fpu_clean_state(void); 1312652af56SColin Percival 1320b7dc0a7SJohn Baldwin SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD, 1330b7dc0a7SJohn Baldwin NULL, 1, "Floating point instructions executed in hardware"); 1343a34a5c3SPoul-Henning Kamp 135*333d0c60SKonstantin Belousov static int use_xsaveopt; 1368c6f8f3dSKonstantin Belousov int use_xsave; /* non-static for cpu_switch.S */ 1378c6f8f3dSKonstantin Belousov uint64_t xsave_mask; /* the same */ 1388c6f8f3dSKonstantin Belousov static struct savefpu *fpu_initialstate; 1398c6f8f3dSKonstantin Belousov 140*333d0c60SKonstantin Belousov struct xsave_area_elm_descr { 141*333d0c60SKonstantin Belousov u_int offset; 142*333d0c60SKonstantin Belousov u_int size; 143*333d0c60SKonstantin Belousov } *xsave_area_desc; 144*333d0c60SKonstantin Belousov 1458c6f8f3dSKonstantin Belousov void 1468c6f8f3dSKonstantin Belousov fpusave(void *addr) 1478c6f8f3dSKonstantin Belousov { 1488c6f8f3dSKonstantin Belousov 1498c6f8f3dSKonstantin Belousov if (use_xsave) 1508c6f8f3dSKonstantin Belousov xsave((char *)addr, xsave_mask); 1518c6f8f3dSKonstantin Belousov else 1528c6f8f3dSKonstantin Belousov fxsave((char *)addr); 1538c6f8f3dSKonstantin Belousov } 1548c6f8f3dSKonstantin Belousov 1558c6f8f3dSKonstantin Belousov static void 1568c6f8f3dSKonstantin Belousov fpurestore(void *addr) 1578c6f8f3dSKonstantin Belousov { 1588c6f8f3dSKonstantin Belousov 1598c6f8f3dSKonstantin Belousov if (use_xsave) 1608c6f8f3dSKonstantin Belousov xrstor((char *)addr, xsave_mask); 1618c6f8f3dSKonstantin Belousov else 1628c6f8f3dSKonstantin Belousov fxrstor((char *)addr); 1638c6f8f3dSKonstantin Belousov } 1643902c3efSSteve Passe 1655b81b6b3SRodney W. Grimes /* 1668c6f8f3dSKonstantin Belousov * Enable XSAVE if supported and allowed by user. 1678c6f8f3dSKonstantin Belousov * Calculate the xsave_mask. 1688c6f8f3dSKonstantin Belousov */ 1698c6f8f3dSKonstantin Belousov static void 1708c6f8f3dSKonstantin Belousov fpuinit_bsp1(void) 1718c6f8f3dSKonstantin Belousov { 1728c6f8f3dSKonstantin Belousov u_int cp[4]; 1738c6f8f3dSKonstantin Belousov uint64_t xsave_mask_user; 1748c6f8f3dSKonstantin Belousov 1758c6f8f3dSKonstantin Belousov if ((cpu_feature2 & CPUID2_XSAVE) != 0) { 1768c6f8f3dSKonstantin Belousov use_xsave = 1; 1778c6f8f3dSKonstantin Belousov TUNABLE_INT_FETCH("hw.use_xsave", &use_xsave); 1788c6f8f3dSKonstantin Belousov } 1798c6f8f3dSKonstantin Belousov if (!use_xsave) 1808c6f8f3dSKonstantin Belousov return; 1818c6f8f3dSKonstantin Belousov 1828c6f8f3dSKonstantin Belousov cpuid_count(0xd, 0x0, cp); 1838c6f8f3dSKonstantin Belousov xsave_mask = XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE; 1848c6f8f3dSKonstantin Belousov if ((cp[0] & xsave_mask) != xsave_mask) 1858c6f8f3dSKonstantin Belousov panic("CPU0 does not support X87 or SSE: %x", cp[0]); 1868c6f8f3dSKonstantin Belousov xsave_mask = ((uint64_t)cp[3] << 32) | cp[0]; 1878c6f8f3dSKonstantin Belousov xsave_mask_user = xsave_mask; 1888c6f8f3dSKonstantin Belousov TUNABLE_ULONG_FETCH("hw.xsave_mask", &xsave_mask_user); 1898c6f8f3dSKonstantin Belousov xsave_mask_user |= XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE; 1908c6f8f3dSKonstantin Belousov xsave_mask &= xsave_mask_user; 191*333d0c60SKonstantin Belousov 192*333d0c60SKonstantin Belousov cpuid_count(0xd, 0x1, cp); 193*333d0c60SKonstantin Belousov if ((cp[0] & CPUID_EXTSTATE_XSAVEOPT) != 0) { 194*333d0c60SKonstantin Belousov /* 195*333d0c60SKonstantin Belousov * Patch the XSAVE instruction in the cpu_switch code 196*333d0c60SKonstantin Belousov * to XSAVEOPT. We assume that XSAVE encoding used 197*333d0c60SKonstantin Belousov * REX byte, and set the bit 4 of the r/m byte. 198*333d0c60SKonstantin Belousov */ 199*333d0c60SKonstantin Belousov ctx_switch_xsave[3] |= 0x10; 200*333d0c60SKonstantin Belousov use_xsaveopt = 1; 201*333d0c60SKonstantin Belousov } 2028c6f8f3dSKonstantin Belousov } 2038c6f8f3dSKonstantin Belousov 2048c6f8f3dSKonstantin Belousov /* 2058c6f8f3dSKonstantin Belousov * Calculate the fpu save area size. 2068c6f8f3dSKonstantin Belousov */ 2078c6f8f3dSKonstantin Belousov static void 2088c6f8f3dSKonstantin Belousov fpuinit_bsp2(void) 2098c6f8f3dSKonstantin Belousov { 2108c6f8f3dSKonstantin Belousov u_int cp[4]; 2118c6f8f3dSKonstantin Belousov 2128c6f8f3dSKonstantin Belousov if (use_xsave) { 2138c6f8f3dSKonstantin Belousov cpuid_count(0xd, 0x0, cp); 2148c6f8f3dSKonstantin Belousov cpu_max_ext_state_size = cp[1]; 2158c6f8f3dSKonstantin Belousov 2168c6f8f3dSKonstantin Belousov /* 2178c6f8f3dSKonstantin Belousov * Reload the cpu_feature2, since we enabled OSXSAVE. 2188c6f8f3dSKonstantin Belousov */ 2198c6f8f3dSKonstantin Belousov do_cpuid(1, cp); 2208c6f8f3dSKonstantin Belousov cpu_feature2 = cp[2]; 2218c6f8f3dSKonstantin Belousov } else 2228c6f8f3dSKonstantin Belousov cpu_max_ext_state_size = sizeof(struct savefpu); 2238c6f8f3dSKonstantin Belousov } 2248c6f8f3dSKonstantin Belousov 2258c6f8f3dSKonstantin Belousov /* 2268c6f8f3dSKonstantin Belousov * Initialize the floating point unit. 227da4113b3SPeter Wemm */ 228398dbb11SPeter Wemm void 2291c89210cSPeter Wemm fpuinit(void) 230da4113b3SPeter Wemm { 2310689bdccSJohn Baldwin register_t saveintr; 23296a7759eSPeter Wemm u_int mxcsr; 233398dbb11SPeter Wemm u_short control; 234da4113b3SPeter Wemm 2358c6f8f3dSKonstantin Belousov if (IS_BSP()) 2368c6f8f3dSKonstantin Belousov fpuinit_bsp1(); 2378c6f8f3dSKonstantin Belousov 2388c6f8f3dSKonstantin Belousov if (use_xsave) { 2398c6f8f3dSKonstantin Belousov load_cr4(rcr4() | CR4_XSAVE); 2407574a595SJohn Baldwin load_xcr(XCR0, xsave_mask); 2418c6f8f3dSKonstantin Belousov } 2428c6f8f3dSKonstantin Belousov 2438c6f8f3dSKonstantin Belousov /* 2448c6f8f3dSKonstantin Belousov * XCR0 shall be set up before CPU can report the save area size. 2458c6f8f3dSKonstantin Belousov */ 2468c6f8f3dSKonstantin Belousov if (IS_BSP()) 2478c6f8f3dSKonstantin Belousov fpuinit_bsp2(); 2488c6f8f3dSKonstantin Belousov 24999753495SKonstantin Belousov /* 25099753495SKonstantin Belousov * It is too early for critical_enter() to work on AP. 25199753495SKonstantin Belousov */ 2520689bdccSJohn Baldwin saveintr = intr_disable(); 2535b81b6b3SRodney W. Grimes stop_emulating(); 2545b81b6b3SRodney W. Grimes fninit(); 255398dbb11SPeter Wemm control = __INITIAL_FPUCW__; 25617275403SJung-uk Kim fldcw(control); 25796a7759eSPeter Wemm mxcsr = __INITIAL_MXCSR__; 25896a7759eSPeter Wemm ldmxcsr(mxcsr); 259a8346a98SJohn Baldwin start_emulating(); 2600689bdccSJohn Baldwin intr_restore(saveintr); 2615b81b6b3SRodney W. Grimes } 2625b81b6b3SRodney W. Grimes 2635b81b6b3SRodney W. Grimes /* 2648c6f8f3dSKonstantin Belousov * On the boot CPU we generate a clean state that is used to 2658c6f8f3dSKonstantin Belousov * initialize the floating point unit when it is first used by a 2668c6f8f3dSKonstantin Belousov * process. 2678c6f8f3dSKonstantin Belousov */ 2688c6f8f3dSKonstantin Belousov static void 2698c6f8f3dSKonstantin Belousov fpuinitstate(void *arg __unused) 2708c6f8f3dSKonstantin Belousov { 2718c6f8f3dSKonstantin Belousov register_t saveintr; 272*333d0c60SKonstantin Belousov int cp[4], i, max_ext_n; 2738c6f8f3dSKonstantin Belousov 2748c6f8f3dSKonstantin Belousov fpu_initialstate = malloc(cpu_max_ext_state_size, M_DEVBUF, 2758c6f8f3dSKonstantin Belousov M_WAITOK | M_ZERO); 2768c6f8f3dSKonstantin Belousov saveintr = intr_disable(); 2778c6f8f3dSKonstantin Belousov stop_emulating(); 2788c6f8f3dSKonstantin Belousov 2798c6f8f3dSKonstantin Belousov fpusave(fpu_initialstate); 2808c6f8f3dSKonstantin Belousov if (fpu_initialstate->sv_env.en_mxcsr_mask) 2818c6f8f3dSKonstantin Belousov cpu_mxcsr_mask = fpu_initialstate->sv_env.en_mxcsr_mask; 2828c6f8f3dSKonstantin Belousov else 2838c6f8f3dSKonstantin Belousov cpu_mxcsr_mask = 0xFFBF; 2848c6f8f3dSKonstantin Belousov 2858c6f8f3dSKonstantin Belousov /* 2868c6f8f3dSKonstantin Belousov * The fninit instruction does not modify XMM registers. The 2878c6f8f3dSKonstantin Belousov * fpusave call dumped the garbage contained in the registers 2888c6f8f3dSKonstantin Belousov * after reset to the initial state saved. Clear XMM 2898c6f8f3dSKonstantin Belousov * registers file image to make the startup program state and 2908c6f8f3dSKonstantin Belousov * signal handler XMM register content predictable. 2918c6f8f3dSKonstantin Belousov */ 2928c6f8f3dSKonstantin Belousov bzero(&fpu_initialstate->sv_xmm[0], sizeof(struct xmmacc)); 2938c6f8f3dSKonstantin Belousov 294*333d0c60SKonstantin Belousov /* 295*333d0c60SKonstantin Belousov * Create a table describing the layout of the CPU Extended 296*333d0c60SKonstantin Belousov * Save Area. 297*333d0c60SKonstantin Belousov */ 298*333d0c60SKonstantin Belousov if (use_xsaveopt) { 299*333d0c60SKonstantin Belousov max_ext_n = flsl(xsave_mask); 300*333d0c60SKonstantin Belousov xsave_area_desc = malloc(max_ext_n * sizeof(struct 301*333d0c60SKonstantin Belousov xsave_area_elm_descr), M_DEVBUF, M_WAITOK | M_ZERO); 302*333d0c60SKonstantin Belousov /* x87 state */ 303*333d0c60SKonstantin Belousov xsave_area_desc[0].offset = 0; 304*333d0c60SKonstantin Belousov xsave_area_desc[0].size = 160; 305*333d0c60SKonstantin Belousov /* XMM */ 306*333d0c60SKonstantin Belousov xsave_area_desc[1].offset = 160; 307*333d0c60SKonstantin Belousov xsave_area_desc[1].size = 288 - 160; 308*333d0c60SKonstantin Belousov 309*333d0c60SKonstantin Belousov for (i = 2; i < max_ext_n; i++) { 310*333d0c60SKonstantin Belousov cpuid_count(0xd, i, cp); 311*333d0c60SKonstantin Belousov xsave_area_desc[i].offset = cp[1]; 312*333d0c60SKonstantin Belousov xsave_area_desc[i].size = cp[0]; 313*333d0c60SKonstantin Belousov } 314*333d0c60SKonstantin Belousov } 315*333d0c60SKonstantin Belousov 3168c6f8f3dSKonstantin Belousov start_emulating(); 3178c6f8f3dSKonstantin Belousov intr_restore(saveintr); 3188c6f8f3dSKonstantin Belousov } 3198c6f8f3dSKonstantin Belousov SYSINIT(fpuinitstate, SI_SUB_DRIVERS, SI_ORDER_ANY, fpuinitstate, NULL); 3208c6f8f3dSKonstantin Belousov 3218c6f8f3dSKonstantin Belousov /* 3225b81b6b3SRodney W. Grimes * Free coprocessor (if we have it). 3235b81b6b3SRodney W. Grimes */ 3245b81b6b3SRodney W. Grimes void 325bf2f09eeSPeter Wemm fpuexit(struct thread *td) 3265b81b6b3SRodney W. Grimes { 3275b81b6b3SRodney W. Grimes 32899753495SKonstantin Belousov critical_enter(); 3291c89210cSPeter Wemm if (curthread == PCPU_GET(fpcurthread)) { 3301c89210cSPeter Wemm stop_emulating(); 3318c6f8f3dSKonstantin Belousov fpusave(PCPU_GET(curpcb)->pcb_save); 3321c89210cSPeter Wemm start_emulating(); 3331c89210cSPeter Wemm PCPU_SET(fpcurthread, 0); 3341c89210cSPeter Wemm } 33599753495SKonstantin Belousov critical_exit(); 3365b81b6b3SRodney W. Grimes } 3375b81b6b3SRodney W. Grimes 33830abe507SJonathan Mini int 339bf2f09eeSPeter Wemm fpuformat() 34030abe507SJonathan Mini { 34130abe507SJonathan Mini 34230abe507SJonathan Mini return (_MC_FPFMT_XMM); 34330abe507SJonathan Mini } 34430abe507SJonathan Mini 3455b81b6b3SRodney W. Grimes /* 346a7674320SMartin Cracauer * The following mechanism is used to ensure that the FPE_... value 347a7674320SMartin Cracauer * that is passed as a trapcode to the signal handler of the user 348a7674320SMartin Cracauer * process does not have more than one bit set. 349a7674320SMartin Cracauer * 350a7674320SMartin Cracauer * Multiple bits may be set if the user process modifies the control 351a7674320SMartin Cracauer * word while a status word bit is already set. While this is a sign 352a7674320SMartin Cracauer * of bad coding, we have no choise than to narrow them down to one 353a7674320SMartin Cracauer * bit, since we must not send a trapcode that is not exactly one of 354a7674320SMartin Cracauer * the FPE_ macros. 355a7674320SMartin Cracauer * 356a7674320SMartin Cracauer * The mechanism has a static table with 127 entries. Each combination 357a7674320SMartin Cracauer * of the 7 FPU status word exception bits directly translates to a 358a7674320SMartin Cracauer * position in this table, where a single FPE_... value is stored. 359a7674320SMartin Cracauer * This FPE_... value stored there is considered the "most important" 360a7674320SMartin Cracauer * of the exception bits and will be sent as the signal code. The 361a7674320SMartin Cracauer * precedence of the bits is based upon Intel Document "Numerical 362a7674320SMartin Cracauer * Applications", Chapter "Special Computational Situations". 363a7674320SMartin Cracauer * 364a7674320SMartin Cracauer * The macro to choose one of these values does these steps: 1) Throw 365a7674320SMartin Cracauer * away status word bits that cannot be masked. 2) Throw away the bits 366a7674320SMartin Cracauer * currently masked in the control word, assuming the user isn't 367a7674320SMartin Cracauer * interested in them anymore. 3) Reinsert status word bit 7 (stack 368a7674320SMartin Cracauer * fault) if it is set, which cannot be masked but must be presered. 369a7674320SMartin Cracauer * 4) Use the remaining bits to point into the trapcode table. 370a7674320SMartin Cracauer * 371a7674320SMartin Cracauer * The 6 maskable bits in order of their preference, as stated in the 372a7674320SMartin Cracauer * above referenced Intel manual: 373a7674320SMartin Cracauer * 1 Invalid operation (FP_X_INV) 374a7674320SMartin Cracauer * 1a Stack underflow 375a7674320SMartin Cracauer * 1b Stack overflow 376a7674320SMartin Cracauer * 1c Operand of unsupported format 377a7674320SMartin Cracauer * 1d SNaN operand. 378a7674320SMartin Cracauer * 2 QNaN operand (not an exception, irrelavant here) 379a7674320SMartin Cracauer * 3 Any other invalid-operation not mentioned above or zero divide 380a7674320SMartin Cracauer * (FP_X_INV, FP_X_DZ) 381a7674320SMartin Cracauer * 4 Denormal operand (FP_X_DNML) 382a7674320SMartin Cracauer * 5 Numeric over/underflow (FP_X_OFL, FP_X_UFL) 383784648c6SMartin Cracauer * 6 Inexact result (FP_X_IMP) 384784648c6SMartin Cracauer */ 385a7674320SMartin Cracauer static char fpetable[128] = { 386a7674320SMartin Cracauer 0, 387a7674320SMartin Cracauer FPE_FLTINV, /* 1 - INV */ 388a7674320SMartin Cracauer FPE_FLTUND, /* 2 - DNML */ 389a7674320SMartin Cracauer FPE_FLTINV, /* 3 - INV | DNML */ 390a7674320SMartin Cracauer FPE_FLTDIV, /* 4 - DZ */ 391a7674320SMartin Cracauer FPE_FLTINV, /* 5 - INV | DZ */ 392a7674320SMartin Cracauer FPE_FLTDIV, /* 6 - DNML | DZ */ 393a7674320SMartin Cracauer FPE_FLTINV, /* 7 - INV | DNML | DZ */ 394a7674320SMartin Cracauer FPE_FLTOVF, /* 8 - OFL */ 395a7674320SMartin Cracauer FPE_FLTINV, /* 9 - INV | OFL */ 396a7674320SMartin Cracauer FPE_FLTUND, /* A - DNML | OFL */ 397a7674320SMartin Cracauer FPE_FLTINV, /* B - INV | DNML | OFL */ 398a7674320SMartin Cracauer FPE_FLTDIV, /* C - DZ | OFL */ 399a7674320SMartin Cracauer FPE_FLTINV, /* D - INV | DZ | OFL */ 400a7674320SMartin Cracauer FPE_FLTDIV, /* E - DNML | DZ | OFL */ 401a7674320SMartin Cracauer FPE_FLTINV, /* F - INV | DNML | DZ | OFL */ 402a7674320SMartin Cracauer FPE_FLTUND, /* 10 - UFL */ 403a7674320SMartin Cracauer FPE_FLTINV, /* 11 - INV | UFL */ 404a7674320SMartin Cracauer FPE_FLTUND, /* 12 - DNML | UFL */ 405a7674320SMartin Cracauer FPE_FLTINV, /* 13 - INV | DNML | UFL */ 406a7674320SMartin Cracauer FPE_FLTDIV, /* 14 - DZ | UFL */ 407a7674320SMartin Cracauer FPE_FLTINV, /* 15 - INV | DZ | UFL */ 408a7674320SMartin Cracauer FPE_FLTDIV, /* 16 - DNML | DZ | UFL */ 409a7674320SMartin Cracauer FPE_FLTINV, /* 17 - INV | DNML | DZ | UFL */ 410a7674320SMartin Cracauer FPE_FLTOVF, /* 18 - OFL | UFL */ 411a7674320SMartin Cracauer FPE_FLTINV, /* 19 - INV | OFL | UFL */ 412a7674320SMartin Cracauer FPE_FLTUND, /* 1A - DNML | OFL | UFL */ 413a7674320SMartin Cracauer FPE_FLTINV, /* 1B - INV | DNML | OFL | UFL */ 414a7674320SMartin Cracauer FPE_FLTDIV, /* 1C - DZ | OFL | UFL */ 415a7674320SMartin Cracauer FPE_FLTINV, /* 1D - INV | DZ | OFL | UFL */ 416a7674320SMartin Cracauer FPE_FLTDIV, /* 1E - DNML | DZ | OFL | UFL */ 417a7674320SMartin Cracauer FPE_FLTINV, /* 1F - INV | DNML | DZ | OFL | UFL */ 418a7674320SMartin Cracauer FPE_FLTRES, /* 20 - IMP */ 419a7674320SMartin Cracauer FPE_FLTINV, /* 21 - INV | IMP */ 420a7674320SMartin Cracauer FPE_FLTUND, /* 22 - DNML | IMP */ 421a7674320SMartin Cracauer FPE_FLTINV, /* 23 - INV | DNML | IMP */ 422a7674320SMartin Cracauer FPE_FLTDIV, /* 24 - DZ | IMP */ 423a7674320SMartin Cracauer FPE_FLTINV, /* 25 - INV | DZ | IMP */ 424a7674320SMartin Cracauer FPE_FLTDIV, /* 26 - DNML | DZ | IMP */ 425a7674320SMartin Cracauer FPE_FLTINV, /* 27 - INV | DNML | DZ | IMP */ 426a7674320SMartin Cracauer FPE_FLTOVF, /* 28 - OFL | IMP */ 427a7674320SMartin Cracauer FPE_FLTINV, /* 29 - INV | OFL | IMP */ 428a7674320SMartin Cracauer FPE_FLTUND, /* 2A - DNML | OFL | IMP */ 429a7674320SMartin Cracauer FPE_FLTINV, /* 2B - INV | DNML | OFL | IMP */ 430a7674320SMartin Cracauer FPE_FLTDIV, /* 2C - DZ | OFL | IMP */ 431a7674320SMartin Cracauer FPE_FLTINV, /* 2D - INV | DZ | OFL | IMP */ 432a7674320SMartin Cracauer FPE_FLTDIV, /* 2E - DNML | DZ | OFL | IMP */ 433a7674320SMartin Cracauer FPE_FLTINV, /* 2F - INV | DNML | DZ | OFL | IMP */ 434a7674320SMartin Cracauer FPE_FLTUND, /* 30 - UFL | IMP */ 435a7674320SMartin Cracauer FPE_FLTINV, /* 31 - INV | UFL | IMP */ 436a7674320SMartin Cracauer FPE_FLTUND, /* 32 - DNML | UFL | IMP */ 437a7674320SMartin Cracauer FPE_FLTINV, /* 33 - INV | DNML | UFL | IMP */ 438a7674320SMartin Cracauer FPE_FLTDIV, /* 34 - DZ | UFL | IMP */ 439a7674320SMartin Cracauer FPE_FLTINV, /* 35 - INV | DZ | UFL | IMP */ 440a7674320SMartin Cracauer FPE_FLTDIV, /* 36 - DNML | DZ | UFL | IMP */ 441a7674320SMartin Cracauer FPE_FLTINV, /* 37 - INV | DNML | DZ | UFL | IMP */ 442a7674320SMartin Cracauer FPE_FLTOVF, /* 38 - OFL | UFL | IMP */ 443a7674320SMartin Cracauer FPE_FLTINV, /* 39 - INV | OFL | UFL | IMP */ 444a7674320SMartin Cracauer FPE_FLTUND, /* 3A - DNML | OFL | UFL | IMP */ 445a7674320SMartin Cracauer FPE_FLTINV, /* 3B - INV | DNML | OFL | UFL | IMP */ 446a7674320SMartin Cracauer FPE_FLTDIV, /* 3C - DZ | OFL | UFL | IMP */ 447a7674320SMartin Cracauer FPE_FLTINV, /* 3D - INV | DZ | OFL | UFL | IMP */ 448a7674320SMartin Cracauer FPE_FLTDIV, /* 3E - DNML | DZ | OFL | UFL | IMP */ 449a7674320SMartin Cracauer FPE_FLTINV, /* 3F - INV | DNML | DZ | OFL | UFL | IMP */ 450a7674320SMartin Cracauer FPE_FLTSUB, /* 40 - STK */ 451a7674320SMartin Cracauer FPE_FLTSUB, /* 41 - INV | STK */ 452a7674320SMartin Cracauer FPE_FLTUND, /* 42 - DNML | STK */ 453a7674320SMartin Cracauer FPE_FLTSUB, /* 43 - INV | DNML | STK */ 454a7674320SMartin Cracauer FPE_FLTDIV, /* 44 - DZ | STK */ 455a7674320SMartin Cracauer FPE_FLTSUB, /* 45 - INV | DZ | STK */ 456a7674320SMartin Cracauer FPE_FLTDIV, /* 46 - DNML | DZ | STK */ 457a7674320SMartin Cracauer FPE_FLTSUB, /* 47 - INV | DNML | DZ | STK */ 458a7674320SMartin Cracauer FPE_FLTOVF, /* 48 - OFL | STK */ 459a7674320SMartin Cracauer FPE_FLTSUB, /* 49 - INV | OFL | STK */ 460a7674320SMartin Cracauer FPE_FLTUND, /* 4A - DNML | OFL | STK */ 461a7674320SMartin Cracauer FPE_FLTSUB, /* 4B - INV | DNML | OFL | STK */ 462a7674320SMartin Cracauer FPE_FLTDIV, /* 4C - DZ | OFL | STK */ 463a7674320SMartin Cracauer FPE_FLTSUB, /* 4D - INV | DZ | OFL | STK */ 464a7674320SMartin Cracauer FPE_FLTDIV, /* 4E - DNML | DZ | OFL | STK */ 465a7674320SMartin Cracauer FPE_FLTSUB, /* 4F - INV | DNML | DZ | OFL | STK */ 466a7674320SMartin Cracauer FPE_FLTUND, /* 50 - UFL | STK */ 467a7674320SMartin Cracauer FPE_FLTSUB, /* 51 - INV | UFL | STK */ 468a7674320SMartin Cracauer FPE_FLTUND, /* 52 - DNML | UFL | STK */ 469a7674320SMartin Cracauer FPE_FLTSUB, /* 53 - INV | DNML | UFL | STK */ 470a7674320SMartin Cracauer FPE_FLTDIV, /* 54 - DZ | UFL | STK */ 471a7674320SMartin Cracauer FPE_FLTSUB, /* 55 - INV | DZ | UFL | STK */ 472a7674320SMartin Cracauer FPE_FLTDIV, /* 56 - DNML | DZ | UFL | STK */ 473a7674320SMartin Cracauer FPE_FLTSUB, /* 57 - INV | DNML | DZ | UFL | STK */ 474a7674320SMartin Cracauer FPE_FLTOVF, /* 58 - OFL | UFL | STK */ 475a7674320SMartin Cracauer FPE_FLTSUB, /* 59 - INV | OFL | UFL | STK */ 476a7674320SMartin Cracauer FPE_FLTUND, /* 5A - DNML | OFL | UFL | STK */ 477a7674320SMartin Cracauer FPE_FLTSUB, /* 5B - INV | DNML | OFL | UFL | STK */ 478a7674320SMartin Cracauer FPE_FLTDIV, /* 5C - DZ | OFL | UFL | STK */ 479a7674320SMartin Cracauer FPE_FLTSUB, /* 5D - INV | DZ | OFL | UFL | STK */ 480a7674320SMartin Cracauer FPE_FLTDIV, /* 5E - DNML | DZ | OFL | UFL | STK */ 481a7674320SMartin Cracauer FPE_FLTSUB, /* 5F - INV | DNML | DZ | OFL | UFL | STK */ 482a7674320SMartin Cracauer FPE_FLTRES, /* 60 - IMP | STK */ 483a7674320SMartin Cracauer FPE_FLTSUB, /* 61 - INV | IMP | STK */ 484a7674320SMartin Cracauer FPE_FLTUND, /* 62 - DNML | IMP | STK */ 485a7674320SMartin Cracauer FPE_FLTSUB, /* 63 - INV | DNML | IMP | STK */ 486a7674320SMartin Cracauer FPE_FLTDIV, /* 64 - DZ | IMP | STK */ 487a7674320SMartin Cracauer FPE_FLTSUB, /* 65 - INV | DZ | IMP | STK */ 488a7674320SMartin Cracauer FPE_FLTDIV, /* 66 - DNML | DZ | IMP | STK */ 489a7674320SMartin Cracauer FPE_FLTSUB, /* 67 - INV | DNML | DZ | IMP | STK */ 490a7674320SMartin Cracauer FPE_FLTOVF, /* 68 - OFL | IMP | STK */ 491a7674320SMartin Cracauer FPE_FLTSUB, /* 69 - INV | OFL | IMP | STK */ 492a7674320SMartin Cracauer FPE_FLTUND, /* 6A - DNML | OFL | IMP | STK */ 493a7674320SMartin Cracauer FPE_FLTSUB, /* 6B - INV | DNML | OFL | IMP | STK */ 494a7674320SMartin Cracauer FPE_FLTDIV, /* 6C - DZ | OFL | IMP | STK */ 495a7674320SMartin Cracauer FPE_FLTSUB, /* 6D - INV | DZ | OFL | IMP | STK */ 496a7674320SMartin Cracauer FPE_FLTDIV, /* 6E - DNML | DZ | OFL | IMP | STK */ 497a7674320SMartin Cracauer FPE_FLTSUB, /* 6F - INV | DNML | DZ | OFL | IMP | STK */ 498a7674320SMartin Cracauer FPE_FLTUND, /* 70 - UFL | IMP | STK */ 499a7674320SMartin Cracauer FPE_FLTSUB, /* 71 - INV | UFL | IMP | STK */ 500a7674320SMartin Cracauer FPE_FLTUND, /* 72 - DNML | UFL | IMP | STK */ 501a7674320SMartin Cracauer FPE_FLTSUB, /* 73 - INV | DNML | UFL | IMP | STK */ 502a7674320SMartin Cracauer FPE_FLTDIV, /* 74 - DZ | UFL | IMP | STK */ 503a7674320SMartin Cracauer FPE_FLTSUB, /* 75 - INV | DZ | UFL | IMP | STK */ 504a7674320SMartin Cracauer FPE_FLTDIV, /* 76 - DNML | DZ | UFL | IMP | STK */ 505a7674320SMartin Cracauer FPE_FLTSUB, /* 77 - INV | DNML | DZ | UFL | IMP | STK */ 506a7674320SMartin Cracauer FPE_FLTOVF, /* 78 - OFL | UFL | IMP | STK */ 507a7674320SMartin Cracauer FPE_FLTSUB, /* 79 - INV | OFL | UFL | IMP | STK */ 508a7674320SMartin Cracauer FPE_FLTUND, /* 7A - DNML | OFL | UFL | IMP | STK */ 509a7674320SMartin Cracauer FPE_FLTSUB, /* 7B - INV | DNML | OFL | UFL | IMP | STK */ 510a7674320SMartin Cracauer FPE_FLTDIV, /* 7C - DZ | OFL | UFL | IMP | STK */ 511a7674320SMartin Cracauer FPE_FLTSUB, /* 7D - INV | DZ | OFL | UFL | IMP | STK */ 512a7674320SMartin Cracauer FPE_FLTDIV, /* 7E - DNML | DZ | OFL | UFL | IMP | STK */ 513a7674320SMartin Cracauer FPE_FLTSUB, /* 7F - INV | DNML | DZ | OFL | UFL | IMP | STK */ 514a7674320SMartin Cracauer }; 515a7674320SMartin Cracauer 516a7674320SMartin Cracauer /* 51737e52b59SBruce Evans * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE. 5185b81b6b3SRodney W. Grimes * 51937e52b59SBruce Evans * Clearing exceptions is necessary mainly to avoid IRQ13 bugs. We now 52037e52b59SBruce Evans * depend on longjmp() restoring a usable state. Restoring the state 52137e52b59SBruce Evans * or examining it might fail if we didn't clear exceptions. 5225b81b6b3SRodney W. Grimes * 523a7674320SMartin Cracauer * The error code chosen will be one of the FPE_... macros. It will be 524a7674320SMartin Cracauer * sent as the second argument to old BSD-style signal handlers and as 525a7674320SMartin Cracauer * "siginfo_t->si_code" (second argument) to SA_SIGINFO signal handlers. 52637e52b59SBruce Evans * 52737e52b59SBruce Evans * XXX the FP state is not preserved across signal handlers. So signal 52837e52b59SBruce Evans * handlers cannot afford to do FP unless they preserve the state or 52937e52b59SBruce Evans * longjmp() out. Both preserving the state and longjmp()ing may be 53037e52b59SBruce Evans * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable 53137e52b59SBruce Evans * solution for signals other than SIGFPE. 5325b81b6b3SRodney W. Grimes */ 5331c1771cbSBruce Evans int 534bf2f09eeSPeter Wemm fputrap() 5355b81b6b3SRodney W. Grimes { 5361c1771cbSBruce Evans u_short control, status; 5375b81b6b3SRodney W. Grimes 53899753495SKonstantin Belousov critical_enter(); 5395b81b6b3SRodney W. Grimes 5405b81b6b3SRodney W. Grimes /* 5411c1771cbSBruce Evans * Interrupt handling (for another interrupt) may have pushed the 5421c1771cbSBruce Evans * state to memory. Fetch the relevant parts of the state from 5431c1771cbSBruce Evans * wherever they are. 5445b81b6b3SRodney W. Grimes */ 5450bbc8826SJohn Baldwin if (PCPU_GET(fpcurthread) != curthread) { 546b40ce416SJulian Elischer control = GET_FPU_CW(curthread); 547b40ce416SJulian Elischer status = GET_FPU_SW(curthread); 5485b81b6b3SRodney W. Grimes } else { 5491c1771cbSBruce Evans fnstcw(&control); 5501c1771cbSBruce Evans fnstsw(&status); 5515b81b6b3SRodney W. Grimes } 5521c1771cbSBruce Evans 55330abe507SJonathan Mini if (PCPU_GET(fpcurthread) == curthread) 5541c1771cbSBruce Evans fnclex(); 55599753495SKonstantin Belousov critical_exit(); 5561c1771cbSBruce Evans return (fpetable[status & ((~control & 0x3f) | 0x40)]); 5575b81b6b3SRodney W. Grimes } 5585b81b6b3SRodney W. Grimes 5595b81b6b3SRodney W. Grimes /* 5605b81b6b3SRodney W. Grimes * Implement device not available (DNA) exception 5615b81b6b3SRodney W. Grimes * 5620bbc8826SJohn Baldwin * It would be better to switch FP context here (if curthread != fpcurthread) 56337e52b59SBruce Evans * and not necessarily for every context switch, but it is too hard to 56437e52b59SBruce Evans * access foreign pcb's. 5655b81b6b3SRodney W. Grimes */ 56630abe507SJonathan Mini 56730abe507SJonathan Mini static int err_count = 0; 56830abe507SJonathan Mini 569a8346a98SJohn Baldwin void 570a8346a98SJohn Baldwin fpudna(void) 5715b81b6b3SRodney W. Grimes { 57230abe507SJonathan Mini struct pcb *pcb; 57305f6ee66SJake Burkholder 57499753495SKonstantin Belousov critical_enter(); 57530abe507SJonathan Mini if (PCPU_GET(fpcurthread) == curthread) { 576bf2f09eeSPeter Wemm printf("fpudna: fpcurthread == curthread %d times\n", 57730abe507SJonathan Mini ++err_count); 57830abe507SJonathan Mini stop_emulating(); 57999753495SKonstantin Belousov critical_exit(); 580a8346a98SJohn Baldwin return; 58130abe507SJonathan Mini } 5820bbc8826SJohn Baldwin if (PCPU_GET(fpcurthread) != NULL) { 583bf2f09eeSPeter Wemm printf("fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n", 58430abe507SJonathan Mini PCPU_GET(fpcurthread), 58530abe507SJonathan Mini PCPU_GET(fpcurthread)->td_proc->p_pid, 58630abe507SJonathan Mini curthread, curthread->td_proc->p_pid); 587bf2f09eeSPeter Wemm panic("fpudna"); 5885b81b6b3SRodney W. Grimes } 5895b81b6b3SRodney W. Grimes stop_emulating(); 5905b81b6b3SRodney W. Grimes /* 591bf2f09eeSPeter Wemm * Record new context early in case frstor causes a trap. 5925b81b6b3SRodney W. Grimes */ 5930bbc8826SJohn Baldwin PCPU_SET(fpcurthread, curthread); 59430abe507SJonathan Mini pcb = PCPU_GET(curpcb); 5959d146ac5SPeter Wemm 5962652af56SColin Percival fpu_clean_state(); 5972652af56SColin Percival 598bf2f09eeSPeter Wemm if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) { 5995b81b6b3SRodney W. Grimes /* 60063de9515SJohn Baldwin * This is the first time this thread has used the FPU or 60163de9515SJohn Baldwin * the PCB doesn't contain a clean FPU state. Explicitly 60263de9515SJohn Baldwin * load an initial state. 603*333d0c60SKonstantin Belousov * 604*333d0c60SKonstantin Belousov * We prefer to restore the state from the actual save 605*333d0c60SKonstantin Belousov * area in PCB instead of directly loading from 606*333d0c60SKonstantin Belousov * fpu_initialstate, to ignite the XSAVEOPT 607*333d0c60SKonstantin Belousov * tracking engine. 6085b81b6b3SRodney W. Grimes */ 609*333d0c60SKonstantin Belousov bcopy(fpu_initialstate, pcb->pcb_save, cpu_max_ext_state_size); 610*333d0c60SKonstantin Belousov fpurestore(pcb->pcb_save); 6112ee8325fSJohn Baldwin if (pcb->pcb_initial_fpucw != __INITIAL_FPUCW__) 61217275403SJung-uk Kim fldcw(pcb->pcb_initial_fpucw); 61360c7c84eSKonstantin Belousov if (PCB_USER_FPU(pcb)) 614e6c006d9SJung-uk Kim set_pcb_flags(pcb, 615e6c006d9SJung-uk Kim PCB_FPUINITDONE | PCB_USERFPUINITDONE); 616e6c006d9SJung-uk Kim else 617e6c006d9SJung-uk Kim set_pcb_flags(pcb, PCB_FPUINITDONE); 6181c89210cSPeter Wemm } else 6198c6f8f3dSKonstantin Belousov fpurestore(pcb->pcb_save); 62099753495SKonstantin Belousov critical_exit(); 6215b81b6b3SRodney W. Grimes } 6225b81b6b3SRodney W. Grimes 62330abe507SJonathan Mini void 624bf2f09eeSPeter Wemm fpudrop() 62530abe507SJonathan Mini { 62630abe507SJonathan Mini struct thread *td; 62730abe507SJonathan Mini 62830abe507SJonathan Mini td = PCPU_GET(fpcurthread); 62999753495SKonstantin Belousov KASSERT(td == curthread, ("fpudrop: fpcurthread != curthread")); 6304a23ecc7SKonstantin Belousov CRITICAL_ASSERT(td); 63130abe507SJonathan Mini PCPU_SET(fpcurthread, NULL); 632e6c006d9SJung-uk Kim clear_pcb_flags(td->td_pcb, PCB_FPUINITDONE); 63330abe507SJonathan Mini start_emulating(); 63430abe507SJonathan Mini } 63530abe507SJonathan Mini 63630abe507SJonathan Mini /* 6375c6eb037SKonstantin Belousov * Get the user state of the FPU into pcb->pcb_user_save without 6385c6eb037SKonstantin Belousov * dropping ownership (if possible). It returns the FPU ownership 6395c6eb037SKonstantin Belousov * status. 64030abe507SJonathan Mini */ 64130abe507SJonathan Mini int 6425c6eb037SKonstantin Belousov fpugetregs(struct thread *td) 6436cf9a08dSKonstantin Belousov { 6446cf9a08dSKonstantin Belousov struct pcb *pcb; 645*333d0c60SKonstantin Belousov uint64_t *xstate_bv, bit; 646*333d0c60SKonstantin Belousov char *sa; 647*333d0c60SKonstantin Belousov int max_ext_n, i; 6486cf9a08dSKonstantin Belousov 6496cf9a08dSKonstantin Belousov pcb = td->td_pcb; 6506cf9a08dSKonstantin Belousov if ((pcb->pcb_flags & PCB_USERFPUINITDONE) == 0) { 6518c6f8f3dSKonstantin Belousov bcopy(fpu_initialstate, get_pcb_user_save_pcb(pcb), 6528c6f8f3dSKonstantin Belousov cpu_max_ext_state_size); 6538c6f8f3dSKonstantin Belousov get_pcb_user_save_pcb(pcb)->sv_env.en_cw = 6548c6f8f3dSKonstantin Belousov pcb->pcb_initial_fpucw; 6555c6eb037SKonstantin Belousov fpuuserinited(td); 6565c6eb037SKonstantin Belousov return (_MC_FPOWNED_PCB); 6576cf9a08dSKonstantin Belousov } 65899753495SKonstantin Belousov critical_enter(); 6596cf9a08dSKonstantin Belousov if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) { 6608c6f8f3dSKonstantin Belousov fpusave(get_pcb_user_save_pcb(pcb)); 66199753495SKonstantin Belousov critical_exit(); 6626cf9a08dSKonstantin Belousov return (_MC_FPOWNED_FPU); 6636cf9a08dSKonstantin Belousov } else { 66499753495SKonstantin Belousov critical_exit(); 665*333d0c60SKonstantin Belousov if (use_xsaveopt) { 666*333d0c60SKonstantin Belousov /* 667*333d0c60SKonstantin Belousov * Handle partially saved state. 668*333d0c60SKonstantin Belousov */ 669*333d0c60SKonstantin Belousov sa = (char *)get_pcb_user_save_pcb(pcb); 670*333d0c60SKonstantin Belousov xstate_bv = (uint64_t *)(sa + sizeof(struct savefpu) + 671*333d0c60SKonstantin Belousov offsetof(struct xstate_hdr, xstate_bv)); 672*333d0c60SKonstantin Belousov max_ext_n = flsl(xsave_mask); 673*333d0c60SKonstantin Belousov for (i = 0; i < max_ext_n; i++) { 674*333d0c60SKonstantin Belousov bit = 1 << i; 675*333d0c60SKonstantin Belousov if ((*xstate_bv & bit) != 0) 676*333d0c60SKonstantin Belousov continue; 677*333d0c60SKonstantin Belousov bcopy((char *)fpu_initialstate + 678*333d0c60SKonstantin Belousov xsave_area_desc[i].offset, 679*333d0c60SKonstantin Belousov sa + xsave_area_desc[i].offset, 680*333d0c60SKonstantin Belousov xsave_area_desc[i].size); 681*333d0c60SKonstantin Belousov *xstate_bv |= bit; 682*333d0c60SKonstantin Belousov } 683*333d0c60SKonstantin Belousov } 6846cf9a08dSKonstantin Belousov return (_MC_FPOWNED_PCB); 6856cf9a08dSKonstantin Belousov } 6866cf9a08dSKonstantin Belousov } 6876cf9a08dSKonstantin Belousov 6885c6eb037SKonstantin Belousov void 6895c6eb037SKonstantin Belousov fpuuserinited(struct thread *td) 69030abe507SJonathan Mini { 6916cf9a08dSKonstantin Belousov struct pcb *pcb; 69230abe507SJonathan Mini 6936cf9a08dSKonstantin Belousov pcb = td->td_pcb; 6945c6eb037SKonstantin Belousov if (PCB_USER_FPU(pcb)) 695e6c006d9SJung-uk Kim set_pcb_flags(pcb, 696e6c006d9SJung-uk Kim PCB_FPUINITDONE | PCB_USERFPUINITDONE); 697e6c006d9SJung-uk Kim else 698e6c006d9SJung-uk Kim set_pcb_flags(pcb, PCB_FPUINITDONE); 69930abe507SJonathan Mini } 70030abe507SJonathan Mini 7018c6f8f3dSKonstantin Belousov int 7028c6f8f3dSKonstantin Belousov fpusetxstate(struct thread *td, char *xfpustate, size_t xfpustate_size) 7038c6f8f3dSKonstantin Belousov { 7048c6f8f3dSKonstantin Belousov struct xstate_hdr *hdr, *ehdr; 7058c6f8f3dSKonstantin Belousov size_t len, max_len; 7068c6f8f3dSKonstantin Belousov uint64_t bv; 7078c6f8f3dSKonstantin Belousov 7088c6f8f3dSKonstantin Belousov /* XXXKIB should we clear all extended state in xstate_bv instead ? */ 7098c6f8f3dSKonstantin Belousov if (xfpustate == NULL) 7108c6f8f3dSKonstantin Belousov return (0); 7118c6f8f3dSKonstantin Belousov if (!use_xsave) 7128c6f8f3dSKonstantin Belousov return (EOPNOTSUPP); 7138c6f8f3dSKonstantin Belousov 7148c6f8f3dSKonstantin Belousov len = xfpustate_size; 7158c6f8f3dSKonstantin Belousov if (len < sizeof(struct xstate_hdr)) 7168c6f8f3dSKonstantin Belousov return (EINVAL); 7178c6f8f3dSKonstantin Belousov max_len = cpu_max_ext_state_size - sizeof(struct savefpu); 7188c6f8f3dSKonstantin Belousov if (len > max_len) 7198c6f8f3dSKonstantin Belousov return (EINVAL); 7208c6f8f3dSKonstantin Belousov 7218c6f8f3dSKonstantin Belousov ehdr = (struct xstate_hdr *)xfpustate; 7228c6f8f3dSKonstantin Belousov bv = ehdr->xstate_bv; 7238c6f8f3dSKonstantin Belousov 7248c6f8f3dSKonstantin Belousov /* 7258c6f8f3dSKonstantin Belousov * Avoid #gp. 7268c6f8f3dSKonstantin Belousov */ 7278c6f8f3dSKonstantin Belousov if (bv & ~xsave_mask) 7288c6f8f3dSKonstantin Belousov return (EINVAL); 7298c6f8f3dSKonstantin Belousov if ((bv & (XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE)) != 7308c6f8f3dSKonstantin Belousov (XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE)) 7318c6f8f3dSKonstantin Belousov return (EINVAL); 7328c6f8f3dSKonstantin Belousov 7338c6f8f3dSKonstantin Belousov hdr = (struct xstate_hdr *)(get_pcb_user_save_td(td) + 1); 7348c6f8f3dSKonstantin Belousov 7358c6f8f3dSKonstantin Belousov hdr->xstate_bv = bv; 7368c6f8f3dSKonstantin Belousov bcopy(xfpustate + sizeof(struct xstate_hdr), 7378c6f8f3dSKonstantin Belousov (char *)(hdr + 1), len - sizeof(struct xstate_hdr)); 7388c6f8f3dSKonstantin Belousov 7398c6f8f3dSKonstantin Belousov return (0); 7408c6f8f3dSKonstantin Belousov } 7418c6f8f3dSKonstantin Belousov 74230abe507SJonathan Mini /* 74330abe507SJonathan Mini * Set the state of the FPU. 74430abe507SJonathan Mini */ 7458c6f8f3dSKonstantin Belousov int 7468c6f8f3dSKonstantin Belousov fpusetregs(struct thread *td, struct savefpu *addr, char *xfpustate, 7478c6f8f3dSKonstantin Belousov size_t xfpustate_size) 7486cf9a08dSKonstantin Belousov { 7496cf9a08dSKonstantin Belousov struct pcb *pcb; 7508c6f8f3dSKonstantin Belousov int error; 7516cf9a08dSKonstantin Belousov 7526cf9a08dSKonstantin Belousov pcb = td->td_pcb; 75399753495SKonstantin Belousov critical_enter(); 7546cf9a08dSKonstantin Belousov if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) { 7558c6f8f3dSKonstantin Belousov error = fpusetxstate(td, xfpustate, xfpustate_size); 7568c6f8f3dSKonstantin Belousov if (error != 0) { 7578c6f8f3dSKonstantin Belousov critical_exit(); 7588c6f8f3dSKonstantin Belousov return (error); 7598c6f8f3dSKonstantin Belousov } 7608c6f8f3dSKonstantin Belousov bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr)); 7618c6f8f3dSKonstantin Belousov fpurestore(get_pcb_user_save_td(td)); 76299753495SKonstantin Belousov critical_exit(); 763e6c006d9SJung-uk Kim set_pcb_flags(pcb, PCB_FPUINITDONE | PCB_USERFPUINITDONE); 7646cf9a08dSKonstantin Belousov } else { 76599753495SKonstantin Belousov critical_exit(); 7668c6f8f3dSKonstantin Belousov error = fpusetxstate(td, xfpustate, xfpustate_size); 7678c6f8f3dSKonstantin Belousov if (error != 0) 7688c6f8f3dSKonstantin Belousov return (error); 7698c6f8f3dSKonstantin Belousov bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr)); 7705c6eb037SKonstantin Belousov fpuuserinited(td); 7716cf9a08dSKonstantin Belousov } 7728c6f8f3dSKonstantin Belousov return (0); 7736cf9a08dSKonstantin Belousov } 7746cf9a08dSKonstantin Belousov 7756182fdbdSPeter Wemm /* 7762652af56SColin Percival * On AuthenticAMD processors, the fxrstor instruction does not restore 7772652af56SColin Percival * the x87's stored last instruction pointer, last data pointer, and last 7782652af56SColin Percival * opcode values, except in the rare case in which the exception summary 7792652af56SColin Percival * (ES) bit in the x87 status word is set to 1. 7802652af56SColin Percival * 7812652af56SColin Percival * In order to avoid leaking this information across processes, we clean 7822652af56SColin Percival * these values by performing a dummy load before executing fxrstor(). 7832652af56SColin Percival */ 7842652af56SColin Percival static void 7852652af56SColin Percival fpu_clean_state(void) 7862652af56SColin Percival { 787b9dda9d6SJohn Baldwin static float dummy_variable = 0.0; 7882652af56SColin Percival u_short status; 7892652af56SColin Percival 7902652af56SColin Percival /* 7912652af56SColin Percival * Clear the ES bit in the x87 status word if it is currently 7922652af56SColin Percival * set, in order to avoid causing a fault in the upcoming load. 7932652af56SColin Percival */ 7942652af56SColin Percival fnstsw(&status); 7952652af56SColin Percival if (status & 0x80) 7962652af56SColin Percival fnclex(); 7972652af56SColin Percival 7982652af56SColin Percival /* 7992652af56SColin Percival * Load the dummy variable into the x87 stack. This mangles 8002652af56SColin Percival * the x87 stack, but we don't care since we're about to call 8012652af56SColin Percival * fxrstor() anyway. 8022652af56SColin Percival */ 80314965052SDimitry Andric __asm __volatile("ffree %%st(7); flds %0" : : "m" (dummy_variable)); 8042652af56SColin Percival } 8052652af56SColin Percival 8062652af56SColin Percival /* 807398dbb11SPeter Wemm * This really sucks. We want the acpi version only, but it requires 808398dbb11SPeter Wemm * the isa_if.h file in order to get the definitions. 8096182fdbdSPeter Wemm */ 810398dbb11SPeter Wemm #include "opt_isa.h" 811afa88623SPeter Wemm #ifdef DEV_ISA 812398dbb11SPeter Wemm #include <isa/isavar.h> 81354f1d0ceSGarrett Wollman /* 8145f063c7bSMike Smith * This sucks up the legacy ISA support assignments from PNPBIOS/ACPI. 81554f1d0ceSGarrett Wollman */ 816398dbb11SPeter Wemm static struct isa_pnp_id fpupnp_ids[] = { 81754f1d0ceSGarrett Wollman { 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */ 81854f1d0ceSGarrett Wollman { 0 } 81954f1d0ceSGarrett Wollman }; 82054f1d0ceSGarrett Wollman 82154f1d0ceSGarrett Wollman static int 822398dbb11SPeter Wemm fpupnp_probe(device_t dev) 82354f1d0ceSGarrett Wollman { 824bb9c06c1SMike Smith int result; 825bf2f09eeSPeter Wemm 826398dbb11SPeter Wemm result = ISA_PNP_PROBE(device_get_parent(dev), dev, fpupnp_ids); 827bf2f09eeSPeter Wemm if (result <= 0) 828bb9c06c1SMike Smith device_quiet(dev); 829bb9c06c1SMike Smith return (result); 83054f1d0ceSGarrett Wollman } 83154f1d0ceSGarrett Wollman 83254f1d0ceSGarrett Wollman static int 833398dbb11SPeter Wemm fpupnp_attach(device_t dev) 83454f1d0ceSGarrett Wollman { 835bf2f09eeSPeter Wemm 83654f1d0ceSGarrett Wollman return (0); 83754f1d0ceSGarrett Wollman } 83854f1d0ceSGarrett Wollman 839398dbb11SPeter Wemm static device_method_t fpupnp_methods[] = { 84054f1d0ceSGarrett Wollman /* Device interface */ 841398dbb11SPeter Wemm DEVMETHOD(device_probe, fpupnp_probe), 842398dbb11SPeter Wemm DEVMETHOD(device_attach, fpupnp_attach), 84354f1d0ceSGarrett Wollman DEVMETHOD(device_detach, bus_generic_detach), 84454f1d0ceSGarrett Wollman DEVMETHOD(device_shutdown, bus_generic_shutdown), 84554f1d0ceSGarrett Wollman DEVMETHOD(device_suspend, bus_generic_suspend), 84654f1d0ceSGarrett Wollman DEVMETHOD(device_resume, bus_generic_resume), 84754f1d0ceSGarrett Wollman 84854f1d0ceSGarrett Wollman { 0, 0 } 84954f1d0ceSGarrett Wollman }; 85054f1d0ceSGarrett Wollman 851398dbb11SPeter Wemm static driver_t fpupnp_driver = { 852398dbb11SPeter Wemm "fpupnp", 853398dbb11SPeter Wemm fpupnp_methods, 85454f1d0ceSGarrett Wollman 1, /* no softc */ 85554f1d0ceSGarrett Wollman }; 85654f1d0ceSGarrett Wollman 857398dbb11SPeter Wemm static devclass_t fpupnp_devclass; 85854f1d0ceSGarrett Wollman 859398dbb11SPeter Wemm DRIVER_MODULE(fpupnp, acpi, fpupnp_driver, fpupnp_devclass, 0, 0); 860586079ccSBruce Evans #endif /* DEV_ISA */ 8616cf9a08dSKonstantin Belousov 8628c6f8f3dSKonstantin Belousov static MALLOC_DEFINE(M_FPUKERN_CTX, "fpukern_ctx", 8638c6f8f3dSKonstantin Belousov "Kernel contexts for FPU state"); 8648c6f8f3dSKonstantin Belousov 8658c6f8f3dSKonstantin Belousov #define FPU_KERN_CTX_FPUINITDONE 0x01 8668c6f8f3dSKonstantin Belousov 8678c6f8f3dSKonstantin Belousov struct fpu_kern_ctx { 8688c6f8f3dSKonstantin Belousov struct savefpu *prev; 8698c6f8f3dSKonstantin Belousov uint32_t flags; 8708c6f8f3dSKonstantin Belousov char hwstate1[]; 8718c6f8f3dSKonstantin Belousov }; 8728c6f8f3dSKonstantin Belousov 8738c6f8f3dSKonstantin Belousov struct fpu_kern_ctx * 8748c6f8f3dSKonstantin Belousov fpu_kern_alloc_ctx(u_int flags) 8758c6f8f3dSKonstantin Belousov { 8768c6f8f3dSKonstantin Belousov struct fpu_kern_ctx *res; 8778c6f8f3dSKonstantin Belousov size_t sz; 8788c6f8f3dSKonstantin Belousov 8798c6f8f3dSKonstantin Belousov sz = sizeof(struct fpu_kern_ctx) + XSAVE_AREA_ALIGN + 8808c6f8f3dSKonstantin Belousov cpu_max_ext_state_size; 8818c6f8f3dSKonstantin Belousov res = malloc(sz, M_FPUKERN_CTX, ((flags & FPU_KERN_NOWAIT) ? 8828c6f8f3dSKonstantin Belousov M_NOWAIT : M_WAITOK) | M_ZERO); 8838c6f8f3dSKonstantin Belousov return (res); 8848c6f8f3dSKonstantin Belousov } 8858c6f8f3dSKonstantin Belousov 8868c6f8f3dSKonstantin Belousov void 8878c6f8f3dSKonstantin Belousov fpu_kern_free_ctx(struct fpu_kern_ctx *ctx) 8888c6f8f3dSKonstantin Belousov { 8898c6f8f3dSKonstantin Belousov 8908c6f8f3dSKonstantin Belousov /* XXXKIB clear the memory ? */ 8918c6f8f3dSKonstantin Belousov free(ctx, M_FPUKERN_CTX); 8928c6f8f3dSKonstantin Belousov } 8938c6f8f3dSKonstantin Belousov 8948c6f8f3dSKonstantin Belousov static struct savefpu * 8958c6f8f3dSKonstantin Belousov fpu_kern_ctx_savefpu(struct fpu_kern_ctx *ctx) 8968c6f8f3dSKonstantin Belousov { 8978c6f8f3dSKonstantin Belousov vm_offset_t p; 8988c6f8f3dSKonstantin Belousov 8998c6f8f3dSKonstantin Belousov p = (vm_offset_t)&ctx->hwstate1; 9008c6f8f3dSKonstantin Belousov p = roundup2(p, XSAVE_AREA_ALIGN); 9018c6f8f3dSKonstantin Belousov return ((struct savefpu *)p); 9028c6f8f3dSKonstantin Belousov } 9038c6f8f3dSKonstantin Belousov 9046cf9a08dSKonstantin Belousov int 9056cf9a08dSKonstantin Belousov fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags) 9066cf9a08dSKonstantin Belousov { 9076cf9a08dSKonstantin Belousov struct pcb *pcb; 9086cf9a08dSKonstantin Belousov 9096cf9a08dSKonstantin Belousov pcb = td->td_pcb; 9108c6f8f3dSKonstantin Belousov KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save == 9118c6f8f3dSKonstantin Belousov get_pcb_user_save_pcb(pcb), ("mangled pcb_save")); 9126cf9a08dSKonstantin Belousov ctx->flags = 0; 9136cf9a08dSKonstantin Belousov if ((pcb->pcb_flags & PCB_FPUINITDONE) != 0) 9146cf9a08dSKonstantin Belousov ctx->flags |= FPU_KERN_CTX_FPUINITDONE; 9156cf9a08dSKonstantin Belousov fpuexit(td); 9166cf9a08dSKonstantin Belousov ctx->prev = pcb->pcb_save; 9178c6f8f3dSKonstantin Belousov pcb->pcb_save = fpu_kern_ctx_savefpu(ctx); 918e6c006d9SJung-uk Kim set_pcb_flags(pcb, PCB_KERNFPU); 919e6c006d9SJung-uk Kim clear_pcb_flags(pcb, PCB_FPUINITDONE); 9206cf9a08dSKonstantin Belousov return (0); 9216cf9a08dSKonstantin Belousov } 9226cf9a08dSKonstantin Belousov 9236cf9a08dSKonstantin Belousov int 9246cf9a08dSKonstantin Belousov fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx) 9256cf9a08dSKonstantin Belousov { 9266cf9a08dSKonstantin Belousov struct pcb *pcb; 9276cf9a08dSKonstantin Belousov 9286cf9a08dSKonstantin Belousov pcb = td->td_pcb; 92999753495SKonstantin Belousov critical_enter(); 9306cf9a08dSKonstantin Belousov if (curthread == PCPU_GET(fpcurthread)) 9316cf9a08dSKonstantin Belousov fpudrop(); 93299753495SKonstantin Belousov critical_exit(); 9336cf9a08dSKonstantin Belousov pcb->pcb_save = ctx->prev; 9348c6f8f3dSKonstantin Belousov if (pcb->pcb_save == get_pcb_user_save_pcb(pcb)) { 935e6c006d9SJung-uk Kim if ((pcb->pcb_flags & PCB_USERFPUINITDONE) != 0) { 936e6c006d9SJung-uk Kim set_pcb_flags(pcb, PCB_FPUINITDONE); 937e6c006d9SJung-uk Kim clear_pcb_flags(pcb, PCB_KERNFPU); 938e6c006d9SJung-uk Kim } else 939e6c006d9SJung-uk Kim clear_pcb_flags(pcb, PCB_FPUINITDONE | PCB_KERNFPU); 9406cf9a08dSKonstantin Belousov } else { 9416cf9a08dSKonstantin Belousov if ((ctx->flags & FPU_KERN_CTX_FPUINITDONE) != 0) 942e6c006d9SJung-uk Kim set_pcb_flags(pcb, PCB_FPUINITDONE); 9436cf9a08dSKonstantin Belousov else 944e6c006d9SJung-uk Kim clear_pcb_flags(pcb, PCB_FPUINITDONE); 9456cf9a08dSKonstantin Belousov KASSERT(!PCB_USER_FPU(pcb), ("unpaired fpu_kern_leave")); 9466cf9a08dSKonstantin Belousov } 9476cf9a08dSKonstantin Belousov return (0); 9486cf9a08dSKonstantin Belousov } 9496cf9a08dSKonstantin Belousov 9506cf9a08dSKonstantin Belousov int 9516cf9a08dSKonstantin Belousov fpu_kern_thread(u_int flags) 9526cf9a08dSKonstantin Belousov { 9536cf9a08dSKonstantin Belousov struct pcb *pcb; 9546cf9a08dSKonstantin Belousov 9556cf9a08dSKonstantin Belousov pcb = PCPU_GET(curpcb); 9566cf9a08dSKonstantin Belousov KASSERT((curthread->td_pflags & TDP_KTHREAD) != 0, 9576cf9a08dSKonstantin Belousov ("Only kthread may use fpu_kern_thread")); 9588c6f8f3dSKonstantin Belousov KASSERT(pcb->pcb_save == get_pcb_user_save_pcb(pcb), 9598c6f8f3dSKonstantin Belousov ("mangled pcb_save")); 9606cf9a08dSKonstantin Belousov KASSERT(PCB_USER_FPU(pcb), ("recursive call")); 9616cf9a08dSKonstantin Belousov 962e6c006d9SJung-uk Kim set_pcb_flags(pcb, PCB_KERNFPU); 9636cf9a08dSKonstantin Belousov return (0); 9646cf9a08dSKonstantin Belousov } 9656cf9a08dSKonstantin Belousov 9666cf9a08dSKonstantin Belousov int 9676cf9a08dSKonstantin Belousov is_fpu_kern_thread(u_int flags) 9686cf9a08dSKonstantin Belousov { 9696cf9a08dSKonstantin Belousov 9706cf9a08dSKonstantin Belousov if ((curthread->td_pflags & TDP_KTHREAD) == 0) 9716cf9a08dSKonstantin Belousov return (0); 9726cf9a08dSKonstantin Belousov return ((PCPU_GET(curpcb)->pcb_flags & PCB_KERNFPU) != 0); 9736cf9a08dSKonstantin Belousov } 974