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 6837e52b59SBruce Evans #define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr))) 695b81b6b3SRodney W. Grimes #define fnclex() __asm("fnclex") 705b81b6b3SRodney W. Grimes #define fninit() __asm("fninit") 711d37f051SBruce Evans #define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr))) 721d37f051SBruce Evans #define fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr))) 739d146ac5SPeter Wemm #define fxrstor(addr) __asm("fxrstor %0" : : "m" (*(addr))) 749d146ac5SPeter Wemm #define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr))) 7571e0fe3aSPeter Wemm #define ldmxcsr(r) __asm __volatile("ldmxcsr %0" : : "m" (r)) 765b81b6b3SRodney W. Grimes #define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \ 775b81b6b3SRodney W. Grimes : : "n" (CR0_TS) : "ax") 785b81b6b3SRodney W. Grimes #define stop_emulating() __asm("clts") 795b81b6b3SRodney W. Grimes 80cf4e1c46SPeter Wemm #else /* !(__GNUCLIKE_ASM && !lint) */ 815b81b6b3SRodney W. Grimes 8289c9a483SAlfred Perlstein void fldcw(caddr_t addr); 8389c9a483SAlfred Perlstein void fnclex(void); 8489c9a483SAlfred Perlstein void fninit(void); 8589c9a483SAlfred Perlstein void fnstcw(caddr_t addr); 8689c9a483SAlfred Perlstein void fnstsw(caddr_t addr); 8789c9a483SAlfred Perlstein void fxsave(caddr_t addr); 8889c9a483SAlfred Perlstein void fxrstor(caddr_t addr); 8989c9a483SAlfred Perlstein void start_emulating(void); 9089c9a483SAlfred Perlstein void stop_emulating(void); 915b81b6b3SRodney W. Grimes 92cf4e1c46SPeter Wemm #endif /* __GNUCLIKE_ASM && !lint */ 935b81b6b3SRodney W. Grimes 946cf9a08dSKonstantin Belousov #define GET_FPU_CW(thread) ((thread)->td_pcb->pcb_save->sv_env.en_cw) 956cf9a08dSKonstantin Belousov #define GET_FPU_SW(thread) ((thread)->td_pcb->pcb_save->sv_env.en_sw) 969d146ac5SPeter Wemm 975b81b6b3SRodney W. Grimes typedef u_char bool_t; 985b81b6b3SRodney W. Grimes 992652af56SColin Percival static void fpu_clean_state(void); 1002652af56SColin Percival 1010b7dc0a7SJohn Baldwin SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD, 1020b7dc0a7SJohn Baldwin NULL, 1, "Floating point instructions executed in hardware"); 1033a34a5c3SPoul-Henning Kamp 10463de9515SJohn Baldwin static struct savefpu fpu_initialstate; 1053902c3efSSteve Passe 1065b81b6b3SRodney W. Grimes /* 107a8346a98SJohn Baldwin * Initialize the floating point unit. On the boot CPU we generate a 108a8346a98SJohn Baldwin * clean state that is used to initialize the floating point unit when 109a8346a98SJohn Baldwin * it is first used by a process. 110da4113b3SPeter Wemm */ 111398dbb11SPeter Wemm void 1121c89210cSPeter Wemm fpuinit(void) 113da4113b3SPeter Wemm { 114398dbb11SPeter Wemm register_t savecrit; 11596a7759eSPeter Wemm u_int mxcsr; 116398dbb11SPeter Wemm u_short control; 117da4113b3SPeter Wemm 11899753495SKonstantin Belousov /* 11999753495SKonstantin Belousov * It is too early for critical_enter() to work on AP. 12099753495SKonstantin Belousov */ 121398dbb11SPeter Wemm savecrit = intr_disable(); 1225b81b6b3SRodney W. Grimes stop_emulating(); 1235b81b6b3SRodney W. Grimes fninit(); 124398dbb11SPeter Wemm control = __INITIAL_FPUCW__; 125398dbb11SPeter Wemm fldcw(&control); 12696a7759eSPeter Wemm mxcsr = __INITIAL_MXCSR__; 12796a7759eSPeter Wemm ldmxcsr(mxcsr); 128a8346a98SJohn Baldwin if (PCPU_GET(cpuid) == 0) { 12963de9515SJohn Baldwin fxsave(&fpu_initialstate); 13063de9515SJohn Baldwin if (fpu_initialstate.sv_env.en_mxcsr_mask) 13163de9515SJohn Baldwin cpu_mxcsr_mask = fpu_initialstate.sv_env.en_mxcsr_mask; 1324d70df3fSDavid Xu else 1334d70df3fSDavid Xu cpu_mxcsr_mask = 0xFFBF; 13463de9515SJohn Baldwin bzero(fpu_initialstate.sv_fp, sizeof(fpu_initialstate.sv_fp)); 13563de9515SJohn Baldwin bzero(fpu_initialstate.sv_xmm, sizeof(fpu_initialstate.sv_xmm)); 136a8346a98SJohn Baldwin } 137a8346a98SJohn Baldwin start_emulating(); 138ba74981eSWarner Losh intr_restore(savecrit); 1395b81b6b3SRodney W. Grimes } 1405b81b6b3SRodney W. Grimes 1415b81b6b3SRodney W. Grimes /* 1425b81b6b3SRodney W. Grimes * Free coprocessor (if we have it). 1435b81b6b3SRodney W. Grimes */ 1445b81b6b3SRodney W. Grimes void 145bf2f09eeSPeter Wemm fpuexit(struct thread *td) 1465b81b6b3SRodney W. Grimes { 1475b81b6b3SRodney W. Grimes 14899753495SKonstantin Belousov critical_enter(); 1491c89210cSPeter Wemm if (curthread == PCPU_GET(fpcurthread)) { 1501c89210cSPeter Wemm stop_emulating(); 1516cf9a08dSKonstantin Belousov fxsave(PCPU_GET(curpcb)->pcb_save); 1521c89210cSPeter Wemm start_emulating(); 1531c89210cSPeter Wemm PCPU_SET(fpcurthread, 0); 1541c89210cSPeter Wemm } 15599753495SKonstantin Belousov critical_exit(); 1565b81b6b3SRodney W. Grimes } 1575b81b6b3SRodney W. Grimes 15830abe507SJonathan Mini int 159bf2f09eeSPeter Wemm fpuformat() 16030abe507SJonathan Mini { 16130abe507SJonathan Mini 16230abe507SJonathan Mini return (_MC_FPFMT_XMM); 16330abe507SJonathan Mini } 16430abe507SJonathan Mini 1655b81b6b3SRodney W. Grimes /* 166a7674320SMartin Cracauer * The following mechanism is used to ensure that the FPE_... value 167a7674320SMartin Cracauer * that is passed as a trapcode to the signal handler of the user 168a7674320SMartin Cracauer * process does not have more than one bit set. 169a7674320SMartin Cracauer * 170a7674320SMartin Cracauer * Multiple bits may be set if the user process modifies the control 171a7674320SMartin Cracauer * word while a status word bit is already set. While this is a sign 172a7674320SMartin Cracauer * of bad coding, we have no choise than to narrow them down to one 173a7674320SMartin Cracauer * bit, since we must not send a trapcode that is not exactly one of 174a7674320SMartin Cracauer * the FPE_ macros. 175a7674320SMartin Cracauer * 176a7674320SMartin Cracauer * The mechanism has a static table with 127 entries. Each combination 177a7674320SMartin Cracauer * of the 7 FPU status word exception bits directly translates to a 178a7674320SMartin Cracauer * position in this table, where a single FPE_... value is stored. 179a7674320SMartin Cracauer * This FPE_... value stored there is considered the "most important" 180a7674320SMartin Cracauer * of the exception bits and will be sent as the signal code. The 181a7674320SMartin Cracauer * precedence of the bits is based upon Intel Document "Numerical 182a7674320SMartin Cracauer * Applications", Chapter "Special Computational Situations". 183a7674320SMartin Cracauer * 184a7674320SMartin Cracauer * The macro to choose one of these values does these steps: 1) Throw 185a7674320SMartin Cracauer * away status word bits that cannot be masked. 2) Throw away the bits 186a7674320SMartin Cracauer * currently masked in the control word, assuming the user isn't 187a7674320SMartin Cracauer * interested in them anymore. 3) Reinsert status word bit 7 (stack 188a7674320SMartin Cracauer * fault) if it is set, which cannot be masked but must be presered. 189a7674320SMartin Cracauer * 4) Use the remaining bits to point into the trapcode table. 190a7674320SMartin Cracauer * 191a7674320SMartin Cracauer * The 6 maskable bits in order of their preference, as stated in the 192a7674320SMartin Cracauer * above referenced Intel manual: 193a7674320SMartin Cracauer * 1 Invalid operation (FP_X_INV) 194a7674320SMartin Cracauer * 1a Stack underflow 195a7674320SMartin Cracauer * 1b Stack overflow 196a7674320SMartin Cracauer * 1c Operand of unsupported format 197a7674320SMartin Cracauer * 1d SNaN operand. 198a7674320SMartin Cracauer * 2 QNaN operand (not an exception, irrelavant here) 199a7674320SMartin Cracauer * 3 Any other invalid-operation not mentioned above or zero divide 200a7674320SMartin Cracauer * (FP_X_INV, FP_X_DZ) 201a7674320SMartin Cracauer * 4 Denormal operand (FP_X_DNML) 202a7674320SMartin Cracauer * 5 Numeric over/underflow (FP_X_OFL, FP_X_UFL) 203784648c6SMartin Cracauer * 6 Inexact result (FP_X_IMP) 204784648c6SMartin Cracauer */ 205a7674320SMartin Cracauer static char fpetable[128] = { 206a7674320SMartin Cracauer 0, 207a7674320SMartin Cracauer FPE_FLTINV, /* 1 - INV */ 208a7674320SMartin Cracauer FPE_FLTUND, /* 2 - DNML */ 209a7674320SMartin Cracauer FPE_FLTINV, /* 3 - INV | DNML */ 210a7674320SMartin Cracauer FPE_FLTDIV, /* 4 - DZ */ 211a7674320SMartin Cracauer FPE_FLTINV, /* 5 - INV | DZ */ 212a7674320SMartin Cracauer FPE_FLTDIV, /* 6 - DNML | DZ */ 213a7674320SMartin Cracauer FPE_FLTINV, /* 7 - INV | DNML | DZ */ 214a7674320SMartin Cracauer FPE_FLTOVF, /* 8 - OFL */ 215a7674320SMartin Cracauer FPE_FLTINV, /* 9 - INV | OFL */ 216a7674320SMartin Cracauer FPE_FLTUND, /* A - DNML | OFL */ 217a7674320SMartin Cracauer FPE_FLTINV, /* B - INV | DNML | OFL */ 218a7674320SMartin Cracauer FPE_FLTDIV, /* C - DZ | OFL */ 219a7674320SMartin Cracauer FPE_FLTINV, /* D - INV | DZ | OFL */ 220a7674320SMartin Cracauer FPE_FLTDIV, /* E - DNML | DZ | OFL */ 221a7674320SMartin Cracauer FPE_FLTINV, /* F - INV | DNML | DZ | OFL */ 222a7674320SMartin Cracauer FPE_FLTUND, /* 10 - UFL */ 223a7674320SMartin Cracauer FPE_FLTINV, /* 11 - INV | UFL */ 224a7674320SMartin Cracauer FPE_FLTUND, /* 12 - DNML | UFL */ 225a7674320SMartin Cracauer FPE_FLTINV, /* 13 - INV | DNML | UFL */ 226a7674320SMartin Cracauer FPE_FLTDIV, /* 14 - DZ | UFL */ 227a7674320SMartin Cracauer FPE_FLTINV, /* 15 - INV | DZ | UFL */ 228a7674320SMartin Cracauer FPE_FLTDIV, /* 16 - DNML | DZ | UFL */ 229a7674320SMartin Cracauer FPE_FLTINV, /* 17 - INV | DNML | DZ | UFL */ 230a7674320SMartin Cracauer FPE_FLTOVF, /* 18 - OFL | UFL */ 231a7674320SMartin Cracauer FPE_FLTINV, /* 19 - INV | OFL | UFL */ 232a7674320SMartin Cracauer FPE_FLTUND, /* 1A - DNML | OFL | UFL */ 233a7674320SMartin Cracauer FPE_FLTINV, /* 1B - INV | DNML | OFL | UFL */ 234a7674320SMartin Cracauer FPE_FLTDIV, /* 1C - DZ | OFL | UFL */ 235a7674320SMartin Cracauer FPE_FLTINV, /* 1D - INV | DZ | OFL | UFL */ 236a7674320SMartin Cracauer FPE_FLTDIV, /* 1E - DNML | DZ | OFL | UFL */ 237a7674320SMartin Cracauer FPE_FLTINV, /* 1F - INV | DNML | DZ | OFL | UFL */ 238a7674320SMartin Cracauer FPE_FLTRES, /* 20 - IMP */ 239a7674320SMartin Cracauer FPE_FLTINV, /* 21 - INV | IMP */ 240a7674320SMartin Cracauer FPE_FLTUND, /* 22 - DNML | IMP */ 241a7674320SMartin Cracauer FPE_FLTINV, /* 23 - INV | DNML | IMP */ 242a7674320SMartin Cracauer FPE_FLTDIV, /* 24 - DZ | IMP */ 243a7674320SMartin Cracauer FPE_FLTINV, /* 25 - INV | DZ | IMP */ 244a7674320SMartin Cracauer FPE_FLTDIV, /* 26 - DNML | DZ | IMP */ 245a7674320SMartin Cracauer FPE_FLTINV, /* 27 - INV | DNML | DZ | IMP */ 246a7674320SMartin Cracauer FPE_FLTOVF, /* 28 - OFL | IMP */ 247a7674320SMartin Cracauer FPE_FLTINV, /* 29 - INV | OFL | IMP */ 248a7674320SMartin Cracauer FPE_FLTUND, /* 2A - DNML | OFL | IMP */ 249a7674320SMartin Cracauer FPE_FLTINV, /* 2B - INV | DNML | OFL | IMP */ 250a7674320SMartin Cracauer FPE_FLTDIV, /* 2C - DZ | OFL | IMP */ 251a7674320SMartin Cracauer FPE_FLTINV, /* 2D - INV | DZ | OFL | IMP */ 252a7674320SMartin Cracauer FPE_FLTDIV, /* 2E - DNML | DZ | OFL | IMP */ 253a7674320SMartin Cracauer FPE_FLTINV, /* 2F - INV | DNML | DZ | OFL | IMP */ 254a7674320SMartin Cracauer FPE_FLTUND, /* 30 - UFL | IMP */ 255a7674320SMartin Cracauer FPE_FLTINV, /* 31 - INV | UFL | IMP */ 256a7674320SMartin Cracauer FPE_FLTUND, /* 32 - DNML | UFL | IMP */ 257a7674320SMartin Cracauer FPE_FLTINV, /* 33 - INV | DNML | UFL | IMP */ 258a7674320SMartin Cracauer FPE_FLTDIV, /* 34 - DZ | UFL | IMP */ 259a7674320SMartin Cracauer FPE_FLTINV, /* 35 - INV | DZ | UFL | IMP */ 260a7674320SMartin Cracauer FPE_FLTDIV, /* 36 - DNML | DZ | UFL | IMP */ 261a7674320SMartin Cracauer FPE_FLTINV, /* 37 - INV | DNML | DZ | UFL | IMP */ 262a7674320SMartin Cracauer FPE_FLTOVF, /* 38 - OFL | UFL | IMP */ 263a7674320SMartin Cracauer FPE_FLTINV, /* 39 - INV | OFL | UFL | IMP */ 264a7674320SMartin Cracauer FPE_FLTUND, /* 3A - DNML | OFL | UFL | IMP */ 265a7674320SMartin Cracauer FPE_FLTINV, /* 3B - INV | DNML | OFL | UFL | IMP */ 266a7674320SMartin Cracauer FPE_FLTDIV, /* 3C - DZ | OFL | UFL | IMP */ 267a7674320SMartin Cracauer FPE_FLTINV, /* 3D - INV | DZ | OFL | UFL | IMP */ 268a7674320SMartin Cracauer FPE_FLTDIV, /* 3E - DNML | DZ | OFL | UFL | IMP */ 269a7674320SMartin Cracauer FPE_FLTINV, /* 3F - INV | DNML | DZ | OFL | UFL | IMP */ 270a7674320SMartin Cracauer FPE_FLTSUB, /* 40 - STK */ 271a7674320SMartin Cracauer FPE_FLTSUB, /* 41 - INV | STK */ 272a7674320SMartin Cracauer FPE_FLTUND, /* 42 - DNML | STK */ 273a7674320SMartin Cracauer FPE_FLTSUB, /* 43 - INV | DNML | STK */ 274a7674320SMartin Cracauer FPE_FLTDIV, /* 44 - DZ | STK */ 275a7674320SMartin Cracauer FPE_FLTSUB, /* 45 - INV | DZ | STK */ 276a7674320SMartin Cracauer FPE_FLTDIV, /* 46 - DNML | DZ | STK */ 277a7674320SMartin Cracauer FPE_FLTSUB, /* 47 - INV | DNML | DZ | STK */ 278a7674320SMartin Cracauer FPE_FLTOVF, /* 48 - OFL | STK */ 279a7674320SMartin Cracauer FPE_FLTSUB, /* 49 - INV | OFL | STK */ 280a7674320SMartin Cracauer FPE_FLTUND, /* 4A - DNML | OFL | STK */ 281a7674320SMartin Cracauer FPE_FLTSUB, /* 4B - INV | DNML | OFL | STK */ 282a7674320SMartin Cracauer FPE_FLTDIV, /* 4C - DZ | OFL | STK */ 283a7674320SMartin Cracauer FPE_FLTSUB, /* 4D - INV | DZ | OFL | STK */ 284a7674320SMartin Cracauer FPE_FLTDIV, /* 4E - DNML | DZ | OFL | STK */ 285a7674320SMartin Cracauer FPE_FLTSUB, /* 4F - INV | DNML | DZ | OFL | STK */ 286a7674320SMartin Cracauer FPE_FLTUND, /* 50 - UFL | STK */ 287a7674320SMartin Cracauer FPE_FLTSUB, /* 51 - INV | UFL | STK */ 288a7674320SMartin Cracauer FPE_FLTUND, /* 52 - DNML | UFL | STK */ 289a7674320SMartin Cracauer FPE_FLTSUB, /* 53 - INV | DNML | UFL | STK */ 290a7674320SMartin Cracauer FPE_FLTDIV, /* 54 - DZ | UFL | STK */ 291a7674320SMartin Cracauer FPE_FLTSUB, /* 55 - INV | DZ | UFL | STK */ 292a7674320SMartin Cracauer FPE_FLTDIV, /* 56 - DNML | DZ | UFL | STK */ 293a7674320SMartin Cracauer FPE_FLTSUB, /* 57 - INV | DNML | DZ | UFL | STK */ 294a7674320SMartin Cracauer FPE_FLTOVF, /* 58 - OFL | UFL | STK */ 295a7674320SMartin Cracauer FPE_FLTSUB, /* 59 - INV | OFL | UFL | STK */ 296a7674320SMartin Cracauer FPE_FLTUND, /* 5A - DNML | OFL | UFL | STK */ 297a7674320SMartin Cracauer FPE_FLTSUB, /* 5B - INV | DNML | OFL | UFL | STK */ 298a7674320SMartin Cracauer FPE_FLTDIV, /* 5C - DZ | OFL | UFL | STK */ 299a7674320SMartin Cracauer FPE_FLTSUB, /* 5D - INV | DZ | OFL | UFL | STK */ 300a7674320SMartin Cracauer FPE_FLTDIV, /* 5E - DNML | DZ | OFL | UFL | STK */ 301a7674320SMartin Cracauer FPE_FLTSUB, /* 5F - INV | DNML | DZ | OFL | UFL | STK */ 302a7674320SMartin Cracauer FPE_FLTRES, /* 60 - IMP | STK */ 303a7674320SMartin Cracauer FPE_FLTSUB, /* 61 - INV | IMP | STK */ 304a7674320SMartin Cracauer FPE_FLTUND, /* 62 - DNML | IMP | STK */ 305a7674320SMartin Cracauer FPE_FLTSUB, /* 63 - INV | DNML | IMP | STK */ 306a7674320SMartin Cracauer FPE_FLTDIV, /* 64 - DZ | IMP | STK */ 307a7674320SMartin Cracauer FPE_FLTSUB, /* 65 - INV | DZ | IMP | STK */ 308a7674320SMartin Cracauer FPE_FLTDIV, /* 66 - DNML | DZ | IMP | STK */ 309a7674320SMartin Cracauer FPE_FLTSUB, /* 67 - INV | DNML | DZ | IMP | STK */ 310a7674320SMartin Cracauer FPE_FLTOVF, /* 68 - OFL | IMP | STK */ 311a7674320SMartin Cracauer FPE_FLTSUB, /* 69 - INV | OFL | IMP | STK */ 312a7674320SMartin Cracauer FPE_FLTUND, /* 6A - DNML | OFL | IMP | STK */ 313a7674320SMartin Cracauer FPE_FLTSUB, /* 6B - INV | DNML | OFL | IMP | STK */ 314a7674320SMartin Cracauer FPE_FLTDIV, /* 6C - DZ | OFL | IMP | STK */ 315a7674320SMartin Cracauer FPE_FLTSUB, /* 6D - INV | DZ | OFL | IMP | STK */ 316a7674320SMartin Cracauer FPE_FLTDIV, /* 6E - DNML | DZ | OFL | IMP | STK */ 317a7674320SMartin Cracauer FPE_FLTSUB, /* 6F - INV | DNML | DZ | OFL | IMP | STK */ 318a7674320SMartin Cracauer FPE_FLTUND, /* 70 - UFL | IMP | STK */ 319a7674320SMartin Cracauer FPE_FLTSUB, /* 71 - INV | UFL | IMP | STK */ 320a7674320SMartin Cracauer FPE_FLTUND, /* 72 - DNML | UFL | IMP | STK */ 321a7674320SMartin Cracauer FPE_FLTSUB, /* 73 - INV | DNML | UFL | IMP | STK */ 322a7674320SMartin Cracauer FPE_FLTDIV, /* 74 - DZ | UFL | IMP | STK */ 323a7674320SMartin Cracauer FPE_FLTSUB, /* 75 - INV | DZ | UFL | IMP | STK */ 324a7674320SMartin Cracauer FPE_FLTDIV, /* 76 - DNML | DZ | UFL | IMP | STK */ 325a7674320SMartin Cracauer FPE_FLTSUB, /* 77 - INV | DNML | DZ | UFL | IMP | STK */ 326a7674320SMartin Cracauer FPE_FLTOVF, /* 78 - OFL | UFL | IMP | STK */ 327a7674320SMartin Cracauer FPE_FLTSUB, /* 79 - INV | OFL | UFL | IMP | STK */ 328a7674320SMartin Cracauer FPE_FLTUND, /* 7A - DNML | OFL | UFL | IMP | STK */ 329a7674320SMartin Cracauer FPE_FLTSUB, /* 7B - INV | DNML | OFL | UFL | IMP | STK */ 330a7674320SMartin Cracauer FPE_FLTDIV, /* 7C - DZ | OFL | UFL | IMP | STK */ 331a7674320SMartin Cracauer FPE_FLTSUB, /* 7D - INV | DZ | OFL | UFL | IMP | STK */ 332a7674320SMartin Cracauer FPE_FLTDIV, /* 7E - DNML | DZ | OFL | UFL | IMP | STK */ 333a7674320SMartin Cracauer FPE_FLTSUB, /* 7F - INV | DNML | DZ | OFL | UFL | IMP | STK */ 334a7674320SMartin Cracauer }; 335a7674320SMartin Cracauer 336a7674320SMartin Cracauer /* 33737e52b59SBruce Evans * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE. 3385b81b6b3SRodney W. Grimes * 33937e52b59SBruce Evans * Clearing exceptions is necessary mainly to avoid IRQ13 bugs. We now 34037e52b59SBruce Evans * depend on longjmp() restoring a usable state. Restoring the state 34137e52b59SBruce Evans * or examining it might fail if we didn't clear exceptions. 3425b81b6b3SRodney W. Grimes * 343a7674320SMartin Cracauer * The error code chosen will be one of the FPE_... macros. It will be 344a7674320SMartin Cracauer * sent as the second argument to old BSD-style signal handlers and as 345a7674320SMartin Cracauer * "siginfo_t->si_code" (second argument) to SA_SIGINFO signal handlers. 34637e52b59SBruce Evans * 34737e52b59SBruce Evans * XXX the FP state is not preserved across signal handlers. So signal 34837e52b59SBruce Evans * handlers cannot afford to do FP unless they preserve the state or 34937e52b59SBruce Evans * longjmp() out. Both preserving the state and longjmp()ing may be 35037e52b59SBruce Evans * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable 35137e52b59SBruce Evans * solution for signals other than SIGFPE. 3525b81b6b3SRodney W. Grimes */ 3531c1771cbSBruce Evans int 354bf2f09eeSPeter Wemm fputrap() 3555b81b6b3SRodney W. Grimes { 3561c1771cbSBruce Evans u_short control, status; 3575b81b6b3SRodney W. Grimes 35899753495SKonstantin Belousov critical_enter(); 3595b81b6b3SRodney W. Grimes 3605b81b6b3SRodney W. Grimes /* 3611c1771cbSBruce Evans * Interrupt handling (for another interrupt) may have pushed the 3621c1771cbSBruce Evans * state to memory. Fetch the relevant parts of the state from 3631c1771cbSBruce Evans * wherever they are. 3645b81b6b3SRodney W. Grimes */ 3650bbc8826SJohn Baldwin if (PCPU_GET(fpcurthread) != curthread) { 366b40ce416SJulian Elischer control = GET_FPU_CW(curthread); 367b40ce416SJulian Elischer status = GET_FPU_SW(curthread); 3685b81b6b3SRodney W. Grimes } else { 3691c1771cbSBruce Evans fnstcw(&control); 3701c1771cbSBruce Evans fnstsw(&status); 3715b81b6b3SRodney W. Grimes } 3721c1771cbSBruce Evans 37330abe507SJonathan Mini if (PCPU_GET(fpcurthread) == curthread) 3741c1771cbSBruce Evans fnclex(); 37599753495SKonstantin Belousov critical_exit(); 3761c1771cbSBruce Evans return (fpetable[status & ((~control & 0x3f) | 0x40)]); 3775b81b6b3SRodney W. Grimes } 3785b81b6b3SRodney W. Grimes 3795b81b6b3SRodney W. Grimes /* 3805b81b6b3SRodney W. Grimes * Implement device not available (DNA) exception 3815b81b6b3SRodney W. Grimes * 3820bbc8826SJohn Baldwin * It would be better to switch FP context here (if curthread != fpcurthread) 38337e52b59SBruce Evans * and not necessarily for every context switch, but it is too hard to 38437e52b59SBruce Evans * access foreign pcb's. 3855b81b6b3SRodney W. Grimes */ 38630abe507SJonathan Mini 38730abe507SJonathan Mini static int err_count = 0; 38830abe507SJonathan Mini 389a8346a98SJohn Baldwin void 390a8346a98SJohn Baldwin fpudna(void) 3915b81b6b3SRodney W. Grimes { 39230abe507SJonathan Mini struct pcb *pcb; 39305f6ee66SJake Burkholder 39499753495SKonstantin Belousov critical_enter(); 39530abe507SJonathan Mini if (PCPU_GET(fpcurthread) == curthread) { 396bf2f09eeSPeter Wemm printf("fpudna: fpcurthread == curthread %d times\n", 39730abe507SJonathan Mini ++err_count); 39830abe507SJonathan Mini stop_emulating(); 39999753495SKonstantin Belousov critical_exit(); 400a8346a98SJohn Baldwin return; 40130abe507SJonathan Mini } 4020bbc8826SJohn Baldwin if (PCPU_GET(fpcurthread) != NULL) { 403bf2f09eeSPeter Wemm printf("fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n", 40430abe507SJonathan Mini PCPU_GET(fpcurthread), 40530abe507SJonathan Mini PCPU_GET(fpcurthread)->td_proc->p_pid, 40630abe507SJonathan Mini curthread, curthread->td_proc->p_pid); 407bf2f09eeSPeter Wemm panic("fpudna"); 4085b81b6b3SRodney W. Grimes } 4095b81b6b3SRodney W. Grimes stop_emulating(); 4105b81b6b3SRodney W. Grimes /* 411bf2f09eeSPeter Wemm * Record new context early in case frstor causes a trap. 4125b81b6b3SRodney W. Grimes */ 4130bbc8826SJohn Baldwin PCPU_SET(fpcurthread, curthread); 41430abe507SJonathan Mini pcb = PCPU_GET(curpcb); 4159d146ac5SPeter Wemm 4162652af56SColin Percival fpu_clean_state(); 4172652af56SColin Percival 418bf2f09eeSPeter Wemm if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) { 4195b81b6b3SRodney W. Grimes /* 42063de9515SJohn Baldwin * This is the first time this thread has used the FPU or 42163de9515SJohn Baldwin * the PCB doesn't contain a clean FPU state. Explicitly 42263de9515SJohn Baldwin * load an initial state. 4235b81b6b3SRodney W. Grimes */ 42463de9515SJohn Baldwin fxrstor(&fpu_initialstate); 4252ee8325fSJohn Baldwin if (pcb->pcb_initial_fpucw != __INITIAL_FPUCW__) 4262ee8325fSJohn Baldwin fldcw(&pcb->pcb_initial_fpucw); 427bf2f09eeSPeter Wemm pcb->pcb_flags |= PCB_FPUINITDONE; 4286cf9a08dSKonstantin Belousov if (PCB_USER_FPU(pcb)) 4296cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_USERFPUINITDONE; 4301c89210cSPeter Wemm } else 4316cf9a08dSKonstantin Belousov fxrstor(pcb->pcb_save); 43299753495SKonstantin Belousov critical_exit(); 4335b81b6b3SRodney W. Grimes } 4345b81b6b3SRodney W. Grimes 43530abe507SJonathan Mini void 436bf2f09eeSPeter Wemm fpudrop() 43730abe507SJonathan Mini { 43830abe507SJonathan Mini struct thread *td; 43930abe507SJonathan Mini 44030abe507SJonathan Mini td = PCPU_GET(fpcurthread); 44199753495SKonstantin Belousov KASSERT(td == curthread, ("fpudrop: fpcurthread != curthread")); 442*4a23ecc7SKonstantin Belousov CRITICAL_ASSERT(td); 44330abe507SJonathan Mini PCPU_SET(fpcurthread, NULL); 444bf2f09eeSPeter Wemm td->td_pcb->pcb_flags &= ~PCB_FPUINITDONE; 44530abe507SJonathan Mini start_emulating(); 44630abe507SJonathan Mini } 44730abe507SJonathan Mini 44830abe507SJonathan Mini /* 44930abe507SJonathan Mini * Get the state of the FPU without dropping ownership (if possible). 45030abe507SJonathan Mini * It returns the FPU ownership status. 45130abe507SJonathan Mini */ 45230abe507SJonathan Mini int 4536cf9a08dSKonstantin Belousov fpugetuserregs(struct thread *td, struct savefpu *addr) 4546cf9a08dSKonstantin Belousov { 4556cf9a08dSKonstantin Belousov struct pcb *pcb; 4566cf9a08dSKonstantin Belousov 4576cf9a08dSKonstantin Belousov pcb = td->td_pcb; 4586cf9a08dSKonstantin Belousov if ((pcb->pcb_flags & PCB_USERFPUINITDONE) == 0) { 4596cf9a08dSKonstantin Belousov bcopy(&fpu_initialstate, addr, sizeof(fpu_initialstate)); 4606cf9a08dSKonstantin Belousov addr->sv_env.en_cw = pcb->pcb_initial_fpucw; 4616cf9a08dSKonstantin Belousov return (_MC_FPOWNED_NONE); 4626cf9a08dSKonstantin Belousov } 46399753495SKonstantin Belousov critical_enter(); 4646cf9a08dSKonstantin Belousov if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) { 4656cf9a08dSKonstantin Belousov fxsave(addr); 46699753495SKonstantin Belousov critical_exit(); 4676cf9a08dSKonstantin Belousov return (_MC_FPOWNED_FPU); 4686cf9a08dSKonstantin Belousov } else { 46999753495SKonstantin Belousov critical_exit(); 4706cf9a08dSKonstantin Belousov bcopy(&pcb->pcb_user_save, addr, sizeof(*addr)); 4716cf9a08dSKonstantin Belousov return (_MC_FPOWNED_PCB); 4726cf9a08dSKonstantin Belousov } 4736cf9a08dSKonstantin Belousov } 4746cf9a08dSKonstantin Belousov 4756cf9a08dSKonstantin Belousov int 476bf2f09eeSPeter Wemm fpugetregs(struct thread *td, struct savefpu *addr) 47730abe507SJonathan Mini { 4786cf9a08dSKonstantin Belousov struct pcb *pcb; 47930abe507SJonathan Mini 4806cf9a08dSKonstantin Belousov pcb = td->td_pcb; 4816cf9a08dSKonstantin Belousov if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) { 48263de9515SJohn Baldwin bcopy(&fpu_initialstate, addr, sizeof(fpu_initialstate)); 4836cf9a08dSKonstantin Belousov addr->sv_env.en_cw = pcb->pcb_initial_fpucw; 48430abe507SJonathan Mini return (_MC_FPOWNED_NONE); 48530abe507SJonathan Mini } 48699753495SKonstantin Belousov critical_enter(); 487fb8aaa76SJeff Roberson if (td == PCPU_GET(fpcurthread)) { 488afa88623SPeter Wemm fxsave(addr); 48999753495SKonstantin Belousov critical_exit(); 49030abe507SJonathan Mini return (_MC_FPOWNED_FPU); 49130abe507SJonathan Mini } else { 49299753495SKonstantin Belousov critical_exit(); 4936cf9a08dSKonstantin Belousov bcopy(pcb->pcb_save, addr, sizeof(*addr)); 49430abe507SJonathan Mini return (_MC_FPOWNED_PCB); 49530abe507SJonathan Mini } 49630abe507SJonathan Mini } 49730abe507SJonathan Mini 49830abe507SJonathan Mini /* 49930abe507SJonathan Mini * Set the state of the FPU. 50030abe507SJonathan Mini */ 50130abe507SJonathan Mini void 5026cf9a08dSKonstantin Belousov fpusetuserregs(struct thread *td, struct savefpu *addr) 5036cf9a08dSKonstantin Belousov { 5046cf9a08dSKonstantin Belousov struct pcb *pcb; 5056cf9a08dSKonstantin Belousov 5066cf9a08dSKonstantin Belousov pcb = td->td_pcb; 50799753495SKonstantin Belousov critical_enter(); 5086cf9a08dSKonstantin Belousov if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) { 5096cf9a08dSKonstantin Belousov fxrstor(addr); 51099753495SKonstantin Belousov critical_exit(); 5116cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_FPUINITDONE | PCB_USERFPUINITDONE; 5126cf9a08dSKonstantin Belousov } else { 51399753495SKonstantin Belousov critical_exit(); 5146cf9a08dSKonstantin Belousov bcopy(addr, &td->td_pcb->pcb_user_save, sizeof(*addr)); 5156cf9a08dSKonstantin Belousov if (PCB_USER_FPU(pcb)) 5166cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_FPUINITDONE; 5176cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_USERFPUINITDONE; 5186cf9a08dSKonstantin Belousov } 5196cf9a08dSKonstantin Belousov } 5206cf9a08dSKonstantin Belousov 5216cf9a08dSKonstantin Belousov void 522bf2f09eeSPeter Wemm fpusetregs(struct thread *td, struct savefpu *addr) 52330abe507SJonathan Mini { 5246cf9a08dSKonstantin Belousov struct pcb *pcb; 52530abe507SJonathan Mini 5266cf9a08dSKonstantin Belousov pcb = td->td_pcb; 52799753495SKonstantin Belousov critical_enter(); 5284c8a7679SJeff Roberson if (td == PCPU_GET(fpcurthread)) { 529afa88623SPeter Wemm fxrstor(addr); 53099753495SKonstantin Belousov critical_exit(); 53130abe507SJonathan Mini } else { 53299753495SKonstantin Belousov critical_exit(); 5336cf9a08dSKonstantin Belousov bcopy(addr, td->td_pcb->pcb_save, sizeof(*addr)); 53430abe507SJonathan Mini } 5356cf9a08dSKonstantin Belousov if (PCB_USER_FPU(pcb)) 5366cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_USERFPUINITDONE; 5376cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_FPUINITDONE; 53830abe507SJonathan Mini } 53930abe507SJonathan Mini 5406182fdbdSPeter Wemm /* 5412652af56SColin Percival * On AuthenticAMD processors, the fxrstor instruction does not restore 5422652af56SColin Percival * the x87's stored last instruction pointer, last data pointer, and last 5432652af56SColin Percival * opcode values, except in the rare case in which the exception summary 5442652af56SColin Percival * (ES) bit in the x87 status word is set to 1. 5452652af56SColin Percival * 5462652af56SColin Percival * In order to avoid leaking this information across processes, we clean 5472652af56SColin Percival * these values by performing a dummy load before executing fxrstor(). 5482652af56SColin Percival */ 5492652af56SColin Percival static void 5502652af56SColin Percival fpu_clean_state(void) 5512652af56SColin Percival { 552b9dda9d6SJohn Baldwin static float dummy_variable = 0.0; 5532652af56SColin Percival u_short status; 5542652af56SColin Percival 5552652af56SColin Percival /* 5562652af56SColin Percival * Clear the ES bit in the x87 status word if it is currently 5572652af56SColin Percival * set, in order to avoid causing a fault in the upcoming load. 5582652af56SColin Percival */ 5592652af56SColin Percival fnstsw(&status); 5602652af56SColin Percival if (status & 0x80) 5612652af56SColin Percival fnclex(); 5622652af56SColin Percival 5632652af56SColin Percival /* 5642652af56SColin Percival * Load the dummy variable into the x87 stack. This mangles 5652652af56SColin Percival * the x87 stack, but we don't care since we're about to call 5662652af56SColin Percival * fxrstor() anyway. 5672652af56SColin Percival */ 5682652af56SColin Percival __asm __volatile("ffree %%st(7); fld %0" : : "m" (dummy_variable)); 5692652af56SColin Percival } 5702652af56SColin Percival 5712652af56SColin Percival /* 572398dbb11SPeter Wemm * This really sucks. We want the acpi version only, but it requires 573398dbb11SPeter Wemm * the isa_if.h file in order to get the definitions. 5746182fdbdSPeter Wemm */ 575398dbb11SPeter Wemm #include "opt_isa.h" 576afa88623SPeter Wemm #ifdef DEV_ISA 577398dbb11SPeter Wemm #include <isa/isavar.h> 57854f1d0ceSGarrett Wollman /* 5795f063c7bSMike Smith * This sucks up the legacy ISA support assignments from PNPBIOS/ACPI. 58054f1d0ceSGarrett Wollman */ 581398dbb11SPeter Wemm static struct isa_pnp_id fpupnp_ids[] = { 58254f1d0ceSGarrett Wollman { 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */ 58354f1d0ceSGarrett Wollman { 0 } 58454f1d0ceSGarrett Wollman }; 58554f1d0ceSGarrett Wollman 58654f1d0ceSGarrett Wollman static int 587398dbb11SPeter Wemm fpupnp_probe(device_t dev) 58854f1d0ceSGarrett Wollman { 589bb9c06c1SMike Smith int result; 590bf2f09eeSPeter Wemm 591398dbb11SPeter Wemm result = ISA_PNP_PROBE(device_get_parent(dev), dev, fpupnp_ids); 592bf2f09eeSPeter Wemm if (result <= 0) 593bb9c06c1SMike Smith device_quiet(dev); 594bb9c06c1SMike Smith return (result); 59554f1d0ceSGarrett Wollman } 59654f1d0ceSGarrett Wollman 59754f1d0ceSGarrett Wollman static int 598398dbb11SPeter Wemm fpupnp_attach(device_t dev) 59954f1d0ceSGarrett Wollman { 600bf2f09eeSPeter Wemm 60154f1d0ceSGarrett Wollman return (0); 60254f1d0ceSGarrett Wollman } 60354f1d0ceSGarrett Wollman 604398dbb11SPeter Wemm static device_method_t fpupnp_methods[] = { 60554f1d0ceSGarrett Wollman /* Device interface */ 606398dbb11SPeter Wemm DEVMETHOD(device_probe, fpupnp_probe), 607398dbb11SPeter Wemm DEVMETHOD(device_attach, fpupnp_attach), 60854f1d0ceSGarrett Wollman DEVMETHOD(device_detach, bus_generic_detach), 60954f1d0ceSGarrett Wollman DEVMETHOD(device_shutdown, bus_generic_shutdown), 61054f1d0ceSGarrett Wollman DEVMETHOD(device_suspend, bus_generic_suspend), 61154f1d0ceSGarrett Wollman DEVMETHOD(device_resume, bus_generic_resume), 61254f1d0ceSGarrett Wollman 61354f1d0ceSGarrett Wollman { 0, 0 } 61454f1d0ceSGarrett Wollman }; 61554f1d0ceSGarrett Wollman 616398dbb11SPeter Wemm static driver_t fpupnp_driver = { 617398dbb11SPeter Wemm "fpupnp", 618398dbb11SPeter Wemm fpupnp_methods, 61954f1d0ceSGarrett Wollman 1, /* no softc */ 62054f1d0ceSGarrett Wollman }; 62154f1d0ceSGarrett Wollman 622398dbb11SPeter Wemm static devclass_t fpupnp_devclass; 62354f1d0ceSGarrett Wollman 624398dbb11SPeter Wemm DRIVER_MODULE(fpupnp, acpi, fpupnp_driver, fpupnp_devclass, 0, 0); 625586079ccSBruce Evans #endif /* DEV_ISA */ 6266cf9a08dSKonstantin Belousov 6276cf9a08dSKonstantin Belousov int 6286cf9a08dSKonstantin Belousov fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags) 6296cf9a08dSKonstantin Belousov { 6306cf9a08dSKonstantin Belousov struct pcb *pcb; 6316cf9a08dSKonstantin Belousov 6326cf9a08dSKonstantin Belousov pcb = td->td_pcb; 6336cf9a08dSKonstantin Belousov KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save == &pcb->pcb_user_save, 6346cf9a08dSKonstantin Belousov ("mangled pcb_save")); 6356cf9a08dSKonstantin Belousov ctx->flags = 0; 6366cf9a08dSKonstantin Belousov if ((pcb->pcb_flags & PCB_FPUINITDONE) != 0) 6376cf9a08dSKonstantin Belousov ctx->flags |= FPU_KERN_CTX_FPUINITDONE; 6386cf9a08dSKonstantin Belousov fpuexit(td); 6396cf9a08dSKonstantin Belousov ctx->prev = pcb->pcb_save; 6406cf9a08dSKonstantin Belousov pcb->pcb_save = &ctx->hwstate; 6416cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_KERNFPU; 6426cf9a08dSKonstantin Belousov pcb->pcb_flags &= ~PCB_FPUINITDONE; 6436cf9a08dSKonstantin Belousov return (0); 6446cf9a08dSKonstantin Belousov } 6456cf9a08dSKonstantin Belousov 6466cf9a08dSKonstantin Belousov int 6476cf9a08dSKonstantin Belousov fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx) 6486cf9a08dSKonstantin Belousov { 6496cf9a08dSKonstantin Belousov struct pcb *pcb; 6506cf9a08dSKonstantin Belousov 6516cf9a08dSKonstantin Belousov pcb = td->td_pcb; 65299753495SKonstantin Belousov critical_enter(); 6536cf9a08dSKonstantin Belousov if (curthread == PCPU_GET(fpcurthread)) 6546cf9a08dSKonstantin Belousov fpudrop(); 65599753495SKonstantin Belousov critical_exit(); 6566cf9a08dSKonstantin Belousov pcb->pcb_save = ctx->prev; 6576cf9a08dSKonstantin Belousov if (pcb->pcb_save == &pcb->pcb_user_save) { 6586cf9a08dSKonstantin Belousov if ((pcb->pcb_flags & PCB_USERFPUINITDONE) != 0) 6596cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_FPUINITDONE; 6606cf9a08dSKonstantin Belousov else 6616cf9a08dSKonstantin Belousov pcb->pcb_flags &= ~PCB_FPUINITDONE; 6626cf9a08dSKonstantin Belousov pcb->pcb_flags &= ~PCB_KERNFPU; 6636cf9a08dSKonstantin Belousov } else { 6646cf9a08dSKonstantin Belousov if ((ctx->flags & FPU_KERN_CTX_FPUINITDONE) != 0) 6656cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_FPUINITDONE; 6666cf9a08dSKonstantin Belousov else 6676cf9a08dSKonstantin Belousov pcb->pcb_flags &= ~PCB_FPUINITDONE; 6686cf9a08dSKonstantin Belousov KASSERT(!PCB_USER_FPU(pcb), ("unpaired fpu_kern_leave")); 6696cf9a08dSKonstantin Belousov } 6706cf9a08dSKonstantin Belousov return (0); 6716cf9a08dSKonstantin Belousov } 6726cf9a08dSKonstantin Belousov 6736cf9a08dSKonstantin Belousov int 6746cf9a08dSKonstantin Belousov fpu_kern_thread(u_int flags) 6756cf9a08dSKonstantin Belousov { 6766cf9a08dSKonstantin Belousov struct pcb *pcb; 6776cf9a08dSKonstantin Belousov 6786cf9a08dSKonstantin Belousov pcb = PCPU_GET(curpcb); 6796cf9a08dSKonstantin Belousov KASSERT((curthread->td_pflags & TDP_KTHREAD) != 0, 6806cf9a08dSKonstantin Belousov ("Only kthread may use fpu_kern_thread")); 6816cf9a08dSKonstantin Belousov KASSERT(pcb->pcb_save == &pcb->pcb_user_save, ("mangled pcb_save")); 6826cf9a08dSKonstantin Belousov KASSERT(PCB_USER_FPU(pcb), ("recursive call")); 6836cf9a08dSKonstantin Belousov 6846cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_KERNFPU; 6856cf9a08dSKonstantin Belousov return (0); 6866cf9a08dSKonstantin Belousov } 6876cf9a08dSKonstantin Belousov 6886cf9a08dSKonstantin Belousov int 6896cf9a08dSKonstantin Belousov is_fpu_kern_thread(u_int flags) 6906cf9a08dSKonstantin Belousov { 6916cf9a08dSKonstantin Belousov 6926cf9a08dSKonstantin Belousov if ((curthread->td_pflags & TDP_KTHREAD) == 0) 6936cf9a08dSKonstantin Belousov return (0); 6946cf9a08dSKonstantin Belousov return ((PCPU_GET(curpcb)->pcb_flags & PCB_KERNFPU) != 0); 6956cf9a08dSKonstantin Belousov } 696