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 68*30402401SJung-uk Kim #define fldcw(addr) __asm __volatile("fldcw %0" : : "m" (*(addr))) 69*30402401SJung-uk Kim #define fnclex() __asm __volatile("fnclex") 70*30402401SJung-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))) 73*30402401SJung-uk Kim #define fxrstor(addr) __asm __volatile("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)) 76*30402401SJung-uk Kim #define start_emulating() __asm __volatile( \ 77*30402401SJung-uk Kim "smsw %%ax; orb %0,%%al; lmsw %%ax" \ 785b81b6b3SRodney W. Grimes : : "n" (CR0_TS) : "ax") 79*30402401SJung-uk Kim #define stop_emulating() __asm __volatile("clts") 805b81b6b3SRodney W. Grimes 81cf4e1c46SPeter Wemm #else /* !(__GNUCLIKE_ASM && !lint) */ 825b81b6b3SRodney W. Grimes 8389c9a483SAlfred Perlstein void fldcw(caddr_t addr); 8489c9a483SAlfred Perlstein void fnclex(void); 8589c9a483SAlfred Perlstein void fninit(void); 8689c9a483SAlfred Perlstein void fnstcw(caddr_t addr); 8789c9a483SAlfred Perlstein void fnstsw(caddr_t addr); 8889c9a483SAlfred Perlstein void fxsave(caddr_t addr); 8989c9a483SAlfred Perlstein void fxrstor(caddr_t addr); 9089c9a483SAlfred Perlstein void start_emulating(void); 9189c9a483SAlfred Perlstein void stop_emulating(void); 925b81b6b3SRodney W. Grimes 93cf4e1c46SPeter Wemm #endif /* __GNUCLIKE_ASM && !lint */ 945b81b6b3SRodney W. Grimes 956cf9a08dSKonstantin Belousov #define GET_FPU_CW(thread) ((thread)->td_pcb->pcb_save->sv_env.en_cw) 966cf9a08dSKonstantin Belousov #define GET_FPU_SW(thread) ((thread)->td_pcb->pcb_save->sv_env.en_sw) 979d146ac5SPeter Wemm 985b81b6b3SRodney W. Grimes typedef u_char bool_t; 995b81b6b3SRodney W. Grimes 1002652af56SColin Percival static void fpu_clean_state(void); 1012652af56SColin Percival 1020b7dc0a7SJohn Baldwin SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD, 1030b7dc0a7SJohn Baldwin NULL, 1, "Floating point instructions executed in hardware"); 1043a34a5c3SPoul-Henning Kamp 10563de9515SJohn Baldwin static struct savefpu fpu_initialstate; 1063902c3efSSteve Passe 1075b81b6b3SRodney W. Grimes /* 108a8346a98SJohn Baldwin * Initialize the floating point unit. On the boot CPU we generate a 109a8346a98SJohn Baldwin * clean state that is used to initialize the floating point unit when 110a8346a98SJohn Baldwin * it is first used by a process. 111da4113b3SPeter Wemm */ 112398dbb11SPeter Wemm void 1131c89210cSPeter Wemm fpuinit(void) 114da4113b3SPeter Wemm { 115398dbb11SPeter Wemm register_t savecrit; 11696a7759eSPeter Wemm u_int mxcsr; 117398dbb11SPeter Wemm u_short control; 118da4113b3SPeter Wemm 11999753495SKonstantin Belousov /* 12099753495SKonstantin Belousov * It is too early for critical_enter() to work on AP. 12199753495SKonstantin Belousov */ 122398dbb11SPeter Wemm savecrit = intr_disable(); 1235b81b6b3SRodney W. Grimes stop_emulating(); 1245b81b6b3SRodney W. Grimes fninit(); 125398dbb11SPeter Wemm control = __INITIAL_FPUCW__; 126398dbb11SPeter Wemm fldcw(&control); 12796a7759eSPeter Wemm mxcsr = __INITIAL_MXCSR__; 12896a7759eSPeter Wemm ldmxcsr(mxcsr); 129a8346a98SJohn Baldwin if (PCPU_GET(cpuid) == 0) { 13063de9515SJohn Baldwin fxsave(&fpu_initialstate); 13163de9515SJohn Baldwin if (fpu_initialstate.sv_env.en_mxcsr_mask) 13263de9515SJohn Baldwin cpu_mxcsr_mask = fpu_initialstate.sv_env.en_mxcsr_mask; 1334d70df3fSDavid Xu else 1344d70df3fSDavid Xu cpu_mxcsr_mask = 0xFFBF; 13563de9515SJohn Baldwin bzero(fpu_initialstate.sv_fp, sizeof(fpu_initialstate.sv_fp)); 13663de9515SJohn Baldwin bzero(fpu_initialstate.sv_xmm, sizeof(fpu_initialstate.sv_xmm)); 137a8346a98SJohn Baldwin } 138a8346a98SJohn Baldwin start_emulating(); 139ba74981eSWarner Losh intr_restore(savecrit); 1405b81b6b3SRodney W. Grimes } 1415b81b6b3SRodney W. Grimes 1425b81b6b3SRodney W. Grimes /* 1435b81b6b3SRodney W. Grimes * Free coprocessor (if we have it). 1445b81b6b3SRodney W. Grimes */ 1455b81b6b3SRodney W. Grimes void 146bf2f09eeSPeter Wemm fpuexit(struct thread *td) 1475b81b6b3SRodney W. Grimes { 1485b81b6b3SRodney W. Grimes 14999753495SKonstantin Belousov critical_enter(); 1501c89210cSPeter Wemm if (curthread == PCPU_GET(fpcurthread)) { 1511c89210cSPeter Wemm stop_emulating(); 1526cf9a08dSKonstantin Belousov fxsave(PCPU_GET(curpcb)->pcb_save); 1531c89210cSPeter Wemm start_emulating(); 1541c89210cSPeter Wemm PCPU_SET(fpcurthread, 0); 1551c89210cSPeter Wemm } 15699753495SKonstantin Belousov critical_exit(); 1575b81b6b3SRodney W. Grimes } 1585b81b6b3SRodney W. Grimes 15930abe507SJonathan Mini int 160bf2f09eeSPeter Wemm fpuformat() 16130abe507SJonathan Mini { 16230abe507SJonathan Mini 16330abe507SJonathan Mini return (_MC_FPFMT_XMM); 16430abe507SJonathan Mini } 16530abe507SJonathan Mini 1665b81b6b3SRodney W. Grimes /* 167a7674320SMartin Cracauer * The following mechanism is used to ensure that the FPE_... value 168a7674320SMartin Cracauer * that is passed as a trapcode to the signal handler of the user 169a7674320SMartin Cracauer * process does not have more than one bit set. 170a7674320SMartin Cracauer * 171a7674320SMartin Cracauer * Multiple bits may be set if the user process modifies the control 172a7674320SMartin Cracauer * word while a status word bit is already set. While this is a sign 173a7674320SMartin Cracauer * of bad coding, we have no choise than to narrow them down to one 174a7674320SMartin Cracauer * bit, since we must not send a trapcode that is not exactly one of 175a7674320SMartin Cracauer * the FPE_ macros. 176a7674320SMartin Cracauer * 177a7674320SMartin Cracauer * The mechanism has a static table with 127 entries. Each combination 178a7674320SMartin Cracauer * of the 7 FPU status word exception bits directly translates to a 179a7674320SMartin Cracauer * position in this table, where a single FPE_... value is stored. 180a7674320SMartin Cracauer * This FPE_... value stored there is considered the "most important" 181a7674320SMartin Cracauer * of the exception bits and will be sent as the signal code. The 182a7674320SMartin Cracauer * precedence of the bits is based upon Intel Document "Numerical 183a7674320SMartin Cracauer * Applications", Chapter "Special Computational Situations". 184a7674320SMartin Cracauer * 185a7674320SMartin Cracauer * The macro to choose one of these values does these steps: 1) Throw 186a7674320SMartin Cracauer * away status word bits that cannot be masked. 2) Throw away the bits 187a7674320SMartin Cracauer * currently masked in the control word, assuming the user isn't 188a7674320SMartin Cracauer * interested in them anymore. 3) Reinsert status word bit 7 (stack 189a7674320SMartin Cracauer * fault) if it is set, which cannot be masked but must be presered. 190a7674320SMartin Cracauer * 4) Use the remaining bits to point into the trapcode table. 191a7674320SMartin Cracauer * 192a7674320SMartin Cracauer * The 6 maskable bits in order of their preference, as stated in the 193a7674320SMartin Cracauer * above referenced Intel manual: 194a7674320SMartin Cracauer * 1 Invalid operation (FP_X_INV) 195a7674320SMartin Cracauer * 1a Stack underflow 196a7674320SMartin Cracauer * 1b Stack overflow 197a7674320SMartin Cracauer * 1c Operand of unsupported format 198a7674320SMartin Cracauer * 1d SNaN operand. 199a7674320SMartin Cracauer * 2 QNaN operand (not an exception, irrelavant here) 200a7674320SMartin Cracauer * 3 Any other invalid-operation not mentioned above or zero divide 201a7674320SMartin Cracauer * (FP_X_INV, FP_X_DZ) 202a7674320SMartin Cracauer * 4 Denormal operand (FP_X_DNML) 203a7674320SMartin Cracauer * 5 Numeric over/underflow (FP_X_OFL, FP_X_UFL) 204784648c6SMartin Cracauer * 6 Inexact result (FP_X_IMP) 205784648c6SMartin Cracauer */ 206a7674320SMartin Cracauer static char fpetable[128] = { 207a7674320SMartin Cracauer 0, 208a7674320SMartin Cracauer FPE_FLTINV, /* 1 - INV */ 209a7674320SMartin Cracauer FPE_FLTUND, /* 2 - DNML */ 210a7674320SMartin Cracauer FPE_FLTINV, /* 3 - INV | DNML */ 211a7674320SMartin Cracauer FPE_FLTDIV, /* 4 - DZ */ 212a7674320SMartin Cracauer FPE_FLTINV, /* 5 - INV | DZ */ 213a7674320SMartin Cracauer FPE_FLTDIV, /* 6 - DNML | DZ */ 214a7674320SMartin Cracauer FPE_FLTINV, /* 7 - INV | DNML | DZ */ 215a7674320SMartin Cracauer FPE_FLTOVF, /* 8 - OFL */ 216a7674320SMartin Cracauer FPE_FLTINV, /* 9 - INV | OFL */ 217a7674320SMartin Cracauer FPE_FLTUND, /* A - DNML | OFL */ 218a7674320SMartin Cracauer FPE_FLTINV, /* B - INV | DNML | OFL */ 219a7674320SMartin Cracauer FPE_FLTDIV, /* C - DZ | OFL */ 220a7674320SMartin Cracauer FPE_FLTINV, /* D - INV | DZ | OFL */ 221a7674320SMartin Cracauer FPE_FLTDIV, /* E - DNML | DZ | OFL */ 222a7674320SMartin Cracauer FPE_FLTINV, /* F - INV | DNML | DZ | OFL */ 223a7674320SMartin Cracauer FPE_FLTUND, /* 10 - UFL */ 224a7674320SMartin Cracauer FPE_FLTINV, /* 11 - INV | UFL */ 225a7674320SMartin Cracauer FPE_FLTUND, /* 12 - DNML | UFL */ 226a7674320SMartin Cracauer FPE_FLTINV, /* 13 - INV | DNML | UFL */ 227a7674320SMartin Cracauer FPE_FLTDIV, /* 14 - DZ | UFL */ 228a7674320SMartin Cracauer FPE_FLTINV, /* 15 - INV | DZ | UFL */ 229a7674320SMartin Cracauer FPE_FLTDIV, /* 16 - DNML | DZ | UFL */ 230a7674320SMartin Cracauer FPE_FLTINV, /* 17 - INV | DNML | DZ | UFL */ 231a7674320SMartin Cracauer FPE_FLTOVF, /* 18 - OFL | UFL */ 232a7674320SMartin Cracauer FPE_FLTINV, /* 19 - INV | OFL | UFL */ 233a7674320SMartin Cracauer FPE_FLTUND, /* 1A - DNML | OFL | UFL */ 234a7674320SMartin Cracauer FPE_FLTINV, /* 1B - INV | DNML | OFL | UFL */ 235a7674320SMartin Cracauer FPE_FLTDIV, /* 1C - DZ | OFL | UFL */ 236a7674320SMartin Cracauer FPE_FLTINV, /* 1D - INV | DZ | OFL | UFL */ 237a7674320SMartin Cracauer FPE_FLTDIV, /* 1E - DNML | DZ | OFL | UFL */ 238a7674320SMartin Cracauer FPE_FLTINV, /* 1F - INV | DNML | DZ | OFL | UFL */ 239a7674320SMartin Cracauer FPE_FLTRES, /* 20 - IMP */ 240a7674320SMartin Cracauer FPE_FLTINV, /* 21 - INV | IMP */ 241a7674320SMartin Cracauer FPE_FLTUND, /* 22 - DNML | IMP */ 242a7674320SMartin Cracauer FPE_FLTINV, /* 23 - INV | DNML | IMP */ 243a7674320SMartin Cracauer FPE_FLTDIV, /* 24 - DZ | IMP */ 244a7674320SMartin Cracauer FPE_FLTINV, /* 25 - INV | DZ | IMP */ 245a7674320SMartin Cracauer FPE_FLTDIV, /* 26 - DNML | DZ | IMP */ 246a7674320SMartin Cracauer FPE_FLTINV, /* 27 - INV | DNML | DZ | IMP */ 247a7674320SMartin Cracauer FPE_FLTOVF, /* 28 - OFL | IMP */ 248a7674320SMartin Cracauer FPE_FLTINV, /* 29 - INV | OFL | IMP */ 249a7674320SMartin Cracauer FPE_FLTUND, /* 2A - DNML | OFL | IMP */ 250a7674320SMartin Cracauer FPE_FLTINV, /* 2B - INV | DNML | OFL | IMP */ 251a7674320SMartin Cracauer FPE_FLTDIV, /* 2C - DZ | OFL | IMP */ 252a7674320SMartin Cracauer FPE_FLTINV, /* 2D - INV | DZ | OFL | IMP */ 253a7674320SMartin Cracauer FPE_FLTDIV, /* 2E - DNML | DZ | OFL | IMP */ 254a7674320SMartin Cracauer FPE_FLTINV, /* 2F - INV | DNML | DZ | OFL | IMP */ 255a7674320SMartin Cracauer FPE_FLTUND, /* 30 - UFL | IMP */ 256a7674320SMartin Cracauer FPE_FLTINV, /* 31 - INV | UFL | IMP */ 257a7674320SMartin Cracauer FPE_FLTUND, /* 32 - DNML | UFL | IMP */ 258a7674320SMartin Cracauer FPE_FLTINV, /* 33 - INV | DNML | UFL | IMP */ 259a7674320SMartin Cracauer FPE_FLTDIV, /* 34 - DZ | UFL | IMP */ 260a7674320SMartin Cracauer FPE_FLTINV, /* 35 - INV | DZ | UFL | IMP */ 261a7674320SMartin Cracauer FPE_FLTDIV, /* 36 - DNML | DZ | UFL | IMP */ 262a7674320SMartin Cracauer FPE_FLTINV, /* 37 - INV | DNML | DZ | UFL | IMP */ 263a7674320SMartin Cracauer FPE_FLTOVF, /* 38 - OFL | UFL | IMP */ 264a7674320SMartin Cracauer FPE_FLTINV, /* 39 - INV | OFL | UFL | IMP */ 265a7674320SMartin Cracauer FPE_FLTUND, /* 3A - DNML | OFL | UFL | IMP */ 266a7674320SMartin Cracauer FPE_FLTINV, /* 3B - INV | DNML | OFL | UFL | IMP */ 267a7674320SMartin Cracauer FPE_FLTDIV, /* 3C - DZ | OFL | UFL | IMP */ 268a7674320SMartin Cracauer FPE_FLTINV, /* 3D - INV | DZ | OFL | UFL | IMP */ 269a7674320SMartin Cracauer FPE_FLTDIV, /* 3E - DNML | DZ | OFL | UFL | IMP */ 270a7674320SMartin Cracauer FPE_FLTINV, /* 3F - INV | DNML | DZ | OFL | UFL | IMP */ 271a7674320SMartin Cracauer FPE_FLTSUB, /* 40 - STK */ 272a7674320SMartin Cracauer FPE_FLTSUB, /* 41 - INV | STK */ 273a7674320SMartin Cracauer FPE_FLTUND, /* 42 - DNML | STK */ 274a7674320SMartin Cracauer FPE_FLTSUB, /* 43 - INV | DNML | STK */ 275a7674320SMartin Cracauer FPE_FLTDIV, /* 44 - DZ | STK */ 276a7674320SMartin Cracauer FPE_FLTSUB, /* 45 - INV | DZ | STK */ 277a7674320SMartin Cracauer FPE_FLTDIV, /* 46 - DNML | DZ | STK */ 278a7674320SMartin Cracauer FPE_FLTSUB, /* 47 - INV | DNML | DZ | STK */ 279a7674320SMartin Cracauer FPE_FLTOVF, /* 48 - OFL | STK */ 280a7674320SMartin Cracauer FPE_FLTSUB, /* 49 - INV | OFL | STK */ 281a7674320SMartin Cracauer FPE_FLTUND, /* 4A - DNML | OFL | STK */ 282a7674320SMartin Cracauer FPE_FLTSUB, /* 4B - INV | DNML | OFL | STK */ 283a7674320SMartin Cracauer FPE_FLTDIV, /* 4C - DZ | OFL | STK */ 284a7674320SMartin Cracauer FPE_FLTSUB, /* 4D - INV | DZ | OFL | STK */ 285a7674320SMartin Cracauer FPE_FLTDIV, /* 4E - DNML | DZ | OFL | STK */ 286a7674320SMartin Cracauer FPE_FLTSUB, /* 4F - INV | DNML | DZ | OFL | STK */ 287a7674320SMartin Cracauer FPE_FLTUND, /* 50 - UFL | STK */ 288a7674320SMartin Cracauer FPE_FLTSUB, /* 51 - INV | UFL | STK */ 289a7674320SMartin Cracauer FPE_FLTUND, /* 52 - DNML | UFL | STK */ 290a7674320SMartin Cracauer FPE_FLTSUB, /* 53 - INV | DNML | UFL | STK */ 291a7674320SMartin Cracauer FPE_FLTDIV, /* 54 - DZ | UFL | STK */ 292a7674320SMartin Cracauer FPE_FLTSUB, /* 55 - INV | DZ | UFL | STK */ 293a7674320SMartin Cracauer FPE_FLTDIV, /* 56 - DNML | DZ | UFL | STK */ 294a7674320SMartin Cracauer FPE_FLTSUB, /* 57 - INV | DNML | DZ | UFL | STK */ 295a7674320SMartin Cracauer FPE_FLTOVF, /* 58 - OFL | UFL | STK */ 296a7674320SMartin Cracauer FPE_FLTSUB, /* 59 - INV | OFL | UFL | STK */ 297a7674320SMartin Cracauer FPE_FLTUND, /* 5A - DNML | OFL | UFL | STK */ 298a7674320SMartin Cracauer FPE_FLTSUB, /* 5B - INV | DNML | OFL | UFL | STK */ 299a7674320SMartin Cracauer FPE_FLTDIV, /* 5C - DZ | OFL | UFL | STK */ 300a7674320SMartin Cracauer FPE_FLTSUB, /* 5D - INV | DZ | OFL | UFL | STK */ 301a7674320SMartin Cracauer FPE_FLTDIV, /* 5E - DNML | DZ | OFL | UFL | STK */ 302a7674320SMartin Cracauer FPE_FLTSUB, /* 5F - INV | DNML | DZ | OFL | UFL | STK */ 303a7674320SMartin Cracauer FPE_FLTRES, /* 60 - IMP | STK */ 304a7674320SMartin Cracauer FPE_FLTSUB, /* 61 - INV | IMP | STK */ 305a7674320SMartin Cracauer FPE_FLTUND, /* 62 - DNML | IMP | STK */ 306a7674320SMartin Cracauer FPE_FLTSUB, /* 63 - INV | DNML | IMP | STK */ 307a7674320SMartin Cracauer FPE_FLTDIV, /* 64 - DZ | IMP | STK */ 308a7674320SMartin Cracauer FPE_FLTSUB, /* 65 - INV | DZ | IMP | STK */ 309a7674320SMartin Cracauer FPE_FLTDIV, /* 66 - DNML | DZ | IMP | STK */ 310a7674320SMartin Cracauer FPE_FLTSUB, /* 67 - INV | DNML | DZ | IMP | STK */ 311a7674320SMartin Cracauer FPE_FLTOVF, /* 68 - OFL | IMP | STK */ 312a7674320SMartin Cracauer FPE_FLTSUB, /* 69 - INV | OFL | IMP | STK */ 313a7674320SMartin Cracauer FPE_FLTUND, /* 6A - DNML | OFL | IMP | STK */ 314a7674320SMartin Cracauer FPE_FLTSUB, /* 6B - INV | DNML | OFL | IMP | STK */ 315a7674320SMartin Cracauer FPE_FLTDIV, /* 6C - DZ | OFL | IMP | STK */ 316a7674320SMartin Cracauer FPE_FLTSUB, /* 6D - INV | DZ | OFL | IMP | STK */ 317a7674320SMartin Cracauer FPE_FLTDIV, /* 6E - DNML | DZ | OFL | IMP | STK */ 318a7674320SMartin Cracauer FPE_FLTSUB, /* 6F - INV | DNML | DZ | OFL | IMP | STK */ 319a7674320SMartin Cracauer FPE_FLTUND, /* 70 - UFL | IMP | STK */ 320a7674320SMartin Cracauer FPE_FLTSUB, /* 71 - INV | UFL | IMP | STK */ 321a7674320SMartin Cracauer FPE_FLTUND, /* 72 - DNML | UFL | IMP | STK */ 322a7674320SMartin Cracauer FPE_FLTSUB, /* 73 - INV | DNML | UFL | IMP | STK */ 323a7674320SMartin Cracauer FPE_FLTDIV, /* 74 - DZ | UFL | IMP | STK */ 324a7674320SMartin Cracauer FPE_FLTSUB, /* 75 - INV | DZ | UFL | IMP | STK */ 325a7674320SMartin Cracauer FPE_FLTDIV, /* 76 - DNML | DZ | UFL | IMP | STK */ 326a7674320SMartin Cracauer FPE_FLTSUB, /* 77 - INV | DNML | DZ | UFL | IMP | STK */ 327a7674320SMartin Cracauer FPE_FLTOVF, /* 78 - OFL | UFL | IMP | STK */ 328a7674320SMartin Cracauer FPE_FLTSUB, /* 79 - INV | OFL | UFL | IMP | STK */ 329a7674320SMartin Cracauer FPE_FLTUND, /* 7A - DNML | OFL | UFL | IMP | STK */ 330a7674320SMartin Cracauer FPE_FLTSUB, /* 7B - INV | DNML | OFL | UFL | IMP | STK */ 331a7674320SMartin Cracauer FPE_FLTDIV, /* 7C - DZ | OFL | UFL | IMP | STK */ 332a7674320SMartin Cracauer FPE_FLTSUB, /* 7D - INV | DZ | OFL | UFL | IMP | STK */ 333a7674320SMartin Cracauer FPE_FLTDIV, /* 7E - DNML | DZ | OFL | UFL | IMP | STK */ 334a7674320SMartin Cracauer FPE_FLTSUB, /* 7F - INV | DNML | DZ | OFL | UFL | IMP | STK */ 335a7674320SMartin Cracauer }; 336a7674320SMartin Cracauer 337a7674320SMartin Cracauer /* 33837e52b59SBruce Evans * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE. 3395b81b6b3SRodney W. Grimes * 34037e52b59SBruce Evans * Clearing exceptions is necessary mainly to avoid IRQ13 bugs. We now 34137e52b59SBruce Evans * depend on longjmp() restoring a usable state. Restoring the state 34237e52b59SBruce Evans * or examining it might fail if we didn't clear exceptions. 3435b81b6b3SRodney W. Grimes * 344a7674320SMartin Cracauer * The error code chosen will be one of the FPE_... macros. It will be 345a7674320SMartin Cracauer * sent as the second argument to old BSD-style signal handlers and as 346a7674320SMartin Cracauer * "siginfo_t->si_code" (second argument) to SA_SIGINFO signal handlers. 34737e52b59SBruce Evans * 34837e52b59SBruce Evans * XXX the FP state is not preserved across signal handlers. So signal 34937e52b59SBruce Evans * handlers cannot afford to do FP unless they preserve the state or 35037e52b59SBruce Evans * longjmp() out. Both preserving the state and longjmp()ing may be 35137e52b59SBruce Evans * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable 35237e52b59SBruce Evans * solution for signals other than SIGFPE. 3535b81b6b3SRodney W. Grimes */ 3541c1771cbSBruce Evans int 355bf2f09eeSPeter Wemm fputrap() 3565b81b6b3SRodney W. Grimes { 3571c1771cbSBruce Evans u_short control, status; 3585b81b6b3SRodney W. Grimes 35999753495SKonstantin Belousov critical_enter(); 3605b81b6b3SRodney W. Grimes 3615b81b6b3SRodney W. Grimes /* 3621c1771cbSBruce Evans * Interrupt handling (for another interrupt) may have pushed the 3631c1771cbSBruce Evans * state to memory. Fetch the relevant parts of the state from 3641c1771cbSBruce Evans * wherever they are. 3655b81b6b3SRodney W. Grimes */ 3660bbc8826SJohn Baldwin if (PCPU_GET(fpcurthread) != curthread) { 367b40ce416SJulian Elischer control = GET_FPU_CW(curthread); 368b40ce416SJulian Elischer status = GET_FPU_SW(curthread); 3695b81b6b3SRodney W. Grimes } else { 3701c1771cbSBruce Evans fnstcw(&control); 3711c1771cbSBruce Evans fnstsw(&status); 3725b81b6b3SRodney W. Grimes } 3731c1771cbSBruce Evans 37430abe507SJonathan Mini if (PCPU_GET(fpcurthread) == curthread) 3751c1771cbSBruce Evans fnclex(); 37699753495SKonstantin Belousov critical_exit(); 3771c1771cbSBruce Evans return (fpetable[status & ((~control & 0x3f) | 0x40)]); 3785b81b6b3SRodney W. Grimes } 3795b81b6b3SRodney W. Grimes 3805b81b6b3SRodney W. Grimes /* 3815b81b6b3SRodney W. Grimes * Implement device not available (DNA) exception 3825b81b6b3SRodney W. Grimes * 3830bbc8826SJohn Baldwin * It would be better to switch FP context here (if curthread != fpcurthread) 38437e52b59SBruce Evans * and not necessarily for every context switch, but it is too hard to 38537e52b59SBruce Evans * access foreign pcb's. 3865b81b6b3SRodney W. Grimes */ 38730abe507SJonathan Mini 38830abe507SJonathan Mini static int err_count = 0; 38930abe507SJonathan Mini 390a8346a98SJohn Baldwin void 391a8346a98SJohn Baldwin fpudna(void) 3925b81b6b3SRodney W. Grimes { 39330abe507SJonathan Mini struct pcb *pcb; 39405f6ee66SJake Burkholder 39599753495SKonstantin Belousov critical_enter(); 39630abe507SJonathan Mini if (PCPU_GET(fpcurthread) == curthread) { 397bf2f09eeSPeter Wemm printf("fpudna: fpcurthread == curthread %d times\n", 39830abe507SJonathan Mini ++err_count); 39930abe507SJonathan Mini stop_emulating(); 40099753495SKonstantin Belousov critical_exit(); 401a8346a98SJohn Baldwin return; 40230abe507SJonathan Mini } 4030bbc8826SJohn Baldwin if (PCPU_GET(fpcurthread) != NULL) { 404bf2f09eeSPeter Wemm printf("fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n", 40530abe507SJonathan Mini PCPU_GET(fpcurthread), 40630abe507SJonathan Mini PCPU_GET(fpcurthread)->td_proc->p_pid, 40730abe507SJonathan Mini curthread, curthread->td_proc->p_pid); 408bf2f09eeSPeter Wemm panic("fpudna"); 4095b81b6b3SRodney W. Grimes } 4105b81b6b3SRodney W. Grimes stop_emulating(); 4115b81b6b3SRodney W. Grimes /* 412bf2f09eeSPeter Wemm * Record new context early in case frstor causes a trap. 4135b81b6b3SRodney W. Grimes */ 4140bbc8826SJohn Baldwin PCPU_SET(fpcurthread, curthread); 41530abe507SJonathan Mini pcb = PCPU_GET(curpcb); 4169d146ac5SPeter Wemm 4172652af56SColin Percival fpu_clean_state(); 4182652af56SColin Percival 419bf2f09eeSPeter Wemm if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) { 4205b81b6b3SRodney W. Grimes /* 42163de9515SJohn Baldwin * This is the first time this thread has used the FPU or 42263de9515SJohn Baldwin * the PCB doesn't contain a clean FPU state. Explicitly 42363de9515SJohn Baldwin * load an initial state. 4245b81b6b3SRodney W. Grimes */ 42563de9515SJohn Baldwin fxrstor(&fpu_initialstate); 4262ee8325fSJohn Baldwin if (pcb->pcb_initial_fpucw != __INITIAL_FPUCW__) 4272ee8325fSJohn Baldwin fldcw(&pcb->pcb_initial_fpucw); 428bf2f09eeSPeter Wemm pcb->pcb_flags |= PCB_FPUINITDONE; 4296cf9a08dSKonstantin Belousov if (PCB_USER_FPU(pcb)) 4306cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_USERFPUINITDONE; 4311c89210cSPeter Wemm } else 4326cf9a08dSKonstantin Belousov fxrstor(pcb->pcb_save); 43399753495SKonstantin Belousov critical_exit(); 4345b81b6b3SRodney W. Grimes } 4355b81b6b3SRodney W. Grimes 43630abe507SJonathan Mini void 437bf2f09eeSPeter Wemm fpudrop() 43830abe507SJonathan Mini { 43930abe507SJonathan Mini struct thread *td; 44030abe507SJonathan Mini 44130abe507SJonathan Mini td = PCPU_GET(fpcurthread); 44299753495SKonstantin Belousov KASSERT(td == curthread, ("fpudrop: fpcurthread != curthread")); 4434a23ecc7SKonstantin Belousov CRITICAL_ASSERT(td); 44430abe507SJonathan Mini PCPU_SET(fpcurthread, NULL); 445bf2f09eeSPeter Wemm td->td_pcb->pcb_flags &= ~PCB_FPUINITDONE; 44630abe507SJonathan Mini start_emulating(); 44730abe507SJonathan Mini } 44830abe507SJonathan Mini 44930abe507SJonathan Mini /* 45030abe507SJonathan Mini * Get the state of the FPU without dropping ownership (if possible). 45130abe507SJonathan Mini * It returns the FPU ownership status. 45230abe507SJonathan Mini */ 45330abe507SJonathan Mini int 4546cf9a08dSKonstantin Belousov fpugetuserregs(struct thread *td, struct savefpu *addr) 4556cf9a08dSKonstantin Belousov { 4566cf9a08dSKonstantin Belousov struct pcb *pcb; 4576cf9a08dSKonstantin Belousov 4586cf9a08dSKonstantin Belousov pcb = td->td_pcb; 4596cf9a08dSKonstantin Belousov if ((pcb->pcb_flags & PCB_USERFPUINITDONE) == 0) { 4606cf9a08dSKonstantin Belousov bcopy(&fpu_initialstate, addr, sizeof(fpu_initialstate)); 4616cf9a08dSKonstantin Belousov addr->sv_env.en_cw = pcb->pcb_initial_fpucw; 4626cf9a08dSKonstantin Belousov return (_MC_FPOWNED_NONE); 4636cf9a08dSKonstantin Belousov } 46499753495SKonstantin Belousov critical_enter(); 4656cf9a08dSKonstantin Belousov if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) { 4666cf9a08dSKonstantin Belousov fxsave(addr); 46799753495SKonstantin Belousov critical_exit(); 4686cf9a08dSKonstantin Belousov return (_MC_FPOWNED_FPU); 4696cf9a08dSKonstantin Belousov } else { 47099753495SKonstantin Belousov critical_exit(); 4716cf9a08dSKonstantin Belousov bcopy(&pcb->pcb_user_save, addr, sizeof(*addr)); 4726cf9a08dSKonstantin Belousov return (_MC_FPOWNED_PCB); 4736cf9a08dSKonstantin Belousov } 4746cf9a08dSKonstantin Belousov } 4756cf9a08dSKonstantin Belousov 4766cf9a08dSKonstantin Belousov int 477bf2f09eeSPeter Wemm fpugetregs(struct thread *td, struct savefpu *addr) 47830abe507SJonathan Mini { 4796cf9a08dSKonstantin Belousov struct pcb *pcb; 48030abe507SJonathan Mini 4816cf9a08dSKonstantin Belousov pcb = td->td_pcb; 4826cf9a08dSKonstantin Belousov if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) { 48363de9515SJohn Baldwin bcopy(&fpu_initialstate, addr, sizeof(fpu_initialstate)); 4846cf9a08dSKonstantin Belousov addr->sv_env.en_cw = pcb->pcb_initial_fpucw; 48530abe507SJonathan Mini return (_MC_FPOWNED_NONE); 48630abe507SJonathan Mini } 48799753495SKonstantin Belousov critical_enter(); 488fb8aaa76SJeff Roberson if (td == PCPU_GET(fpcurthread)) { 489afa88623SPeter Wemm fxsave(addr); 49099753495SKonstantin Belousov critical_exit(); 49130abe507SJonathan Mini return (_MC_FPOWNED_FPU); 49230abe507SJonathan Mini } else { 49399753495SKonstantin Belousov critical_exit(); 4946cf9a08dSKonstantin Belousov bcopy(pcb->pcb_save, addr, sizeof(*addr)); 49530abe507SJonathan Mini return (_MC_FPOWNED_PCB); 49630abe507SJonathan Mini } 49730abe507SJonathan Mini } 49830abe507SJonathan Mini 49930abe507SJonathan Mini /* 50030abe507SJonathan Mini * Set the state of the FPU. 50130abe507SJonathan Mini */ 50230abe507SJonathan Mini void 5036cf9a08dSKonstantin Belousov fpusetuserregs(struct thread *td, struct savefpu *addr) 5046cf9a08dSKonstantin Belousov { 5056cf9a08dSKonstantin Belousov struct pcb *pcb; 5066cf9a08dSKonstantin Belousov 5076cf9a08dSKonstantin Belousov pcb = td->td_pcb; 50899753495SKonstantin Belousov critical_enter(); 5096cf9a08dSKonstantin Belousov if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) { 5106cf9a08dSKonstantin Belousov fxrstor(addr); 51199753495SKonstantin Belousov critical_exit(); 5126cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_FPUINITDONE | PCB_USERFPUINITDONE; 5136cf9a08dSKonstantin Belousov } else { 51499753495SKonstantin Belousov critical_exit(); 5156cf9a08dSKonstantin Belousov bcopy(addr, &td->td_pcb->pcb_user_save, sizeof(*addr)); 5166cf9a08dSKonstantin Belousov if (PCB_USER_FPU(pcb)) 5176cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_FPUINITDONE; 5186cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_USERFPUINITDONE; 5196cf9a08dSKonstantin Belousov } 5206cf9a08dSKonstantin Belousov } 5216cf9a08dSKonstantin Belousov 5226cf9a08dSKonstantin Belousov void 523bf2f09eeSPeter Wemm fpusetregs(struct thread *td, struct savefpu *addr) 52430abe507SJonathan Mini { 5256cf9a08dSKonstantin Belousov struct pcb *pcb; 52630abe507SJonathan Mini 5276cf9a08dSKonstantin Belousov pcb = td->td_pcb; 52899753495SKonstantin Belousov critical_enter(); 5294c8a7679SJeff Roberson if (td == PCPU_GET(fpcurthread)) { 530afa88623SPeter Wemm fxrstor(addr); 53199753495SKonstantin Belousov critical_exit(); 53230abe507SJonathan Mini } else { 53399753495SKonstantin Belousov critical_exit(); 5346cf9a08dSKonstantin Belousov bcopy(addr, td->td_pcb->pcb_save, sizeof(*addr)); 53530abe507SJonathan Mini } 5366cf9a08dSKonstantin Belousov if (PCB_USER_FPU(pcb)) 5376cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_USERFPUINITDONE; 5386cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_FPUINITDONE; 53930abe507SJonathan Mini } 54030abe507SJonathan Mini 5416182fdbdSPeter Wemm /* 5422652af56SColin Percival * On AuthenticAMD processors, the fxrstor instruction does not restore 5432652af56SColin Percival * the x87's stored last instruction pointer, last data pointer, and last 5442652af56SColin Percival * opcode values, except in the rare case in which the exception summary 5452652af56SColin Percival * (ES) bit in the x87 status word is set to 1. 5462652af56SColin Percival * 5472652af56SColin Percival * In order to avoid leaking this information across processes, we clean 5482652af56SColin Percival * these values by performing a dummy load before executing fxrstor(). 5492652af56SColin Percival */ 5502652af56SColin Percival static void 5512652af56SColin Percival fpu_clean_state(void) 5522652af56SColin Percival { 553b9dda9d6SJohn Baldwin static float dummy_variable = 0.0; 5542652af56SColin Percival u_short status; 5552652af56SColin Percival 5562652af56SColin Percival /* 5572652af56SColin Percival * Clear the ES bit in the x87 status word if it is currently 5582652af56SColin Percival * set, in order to avoid causing a fault in the upcoming load. 5592652af56SColin Percival */ 5602652af56SColin Percival fnstsw(&status); 5612652af56SColin Percival if (status & 0x80) 5622652af56SColin Percival fnclex(); 5632652af56SColin Percival 5642652af56SColin Percival /* 5652652af56SColin Percival * Load the dummy variable into the x87 stack. This mangles 5662652af56SColin Percival * the x87 stack, but we don't care since we're about to call 5672652af56SColin Percival * fxrstor() anyway. 5682652af56SColin Percival */ 5692652af56SColin Percival __asm __volatile("ffree %%st(7); fld %0" : : "m" (dummy_variable)); 5702652af56SColin Percival } 5712652af56SColin Percival 5722652af56SColin Percival /* 573398dbb11SPeter Wemm * This really sucks. We want the acpi version only, but it requires 574398dbb11SPeter Wemm * the isa_if.h file in order to get the definitions. 5756182fdbdSPeter Wemm */ 576398dbb11SPeter Wemm #include "opt_isa.h" 577afa88623SPeter Wemm #ifdef DEV_ISA 578398dbb11SPeter Wemm #include <isa/isavar.h> 57954f1d0ceSGarrett Wollman /* 5805f063c7bSMike Smith * This sucks up the legacy ISA support assignments from PNPBIOS/ACPI. 58154f1d0ceSGarrett Wollman */ 582398dbb11SPeter Wemm static struct isa_pnp_id fpupnp_ids[] = { 58354f1d0ceSGarrett Wollman { 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */ 58454f1d0ceSGarrett Wollman { 0 } 58554f1d0ceSGarrett Wollman }; 58654f1d0ceSGarrett Wollman 58754f1d0ceSGarrett Wollman static int 588398dbb11SPeter Wemm fpupnp_probe(device_t dev) 58954f1d0ceSGarrett Wollman { 590bb9c06c1SMike Smith int result; 591bf2f09eeSPeter Wemm 592398dbb11SPeter Wemm result = ISA_PNP_PROBE(device_get_parent(dev), dev, fpupnp_ids); 593bf2f09eeSPeter Wemm if (result <= 0) 594bb9c06c1SMike Smith device_quiet(dev); 595bb9c06c1SMike Smith return (result); 59654f1d0ceSGarrett Wollman } 59754f1d0ceSGarrett Wollman 59854f1d0ceSGarrett Wollman static int 599398dbb11SPeter Wemm fpupnp_attach(device_t dev) 60054f1d0ceSGarrett Wollman { 601bf2f09eeSPeter Wemm 60254f1d0ceSGarrett Wollman return (0); 60354f1d0ceSGarrett Wollman } 60454f1d0ceSGarrett Wollman 605398dbb11SPeter Wemm static device_method_t fpupnp_methods[] = { 60654f1d0ceSGarrett Wollman /* Device interface */ 607398dbb11SPeter Wemm DEVMETHOD(device_probe, fpupnp_probe), 608398dbb11SPeter Wemm DEVMETHOD(device_attach, fpupnp_attach), 60954f1d0ceSGarrett Wollman DEVMETHOD(device_detach, bus_generic_detach), 61054f1d0ceSGarrett Wollman DEVMETHOD(device_shutdown, bus_generic_shutdown), 61154f1d0ceSGarrett Wollman DEVMETHOD(device_suspend, bus_generic_suspend), 61254f1d0ceSGarrett Wollman DEVMETHOD(device_resume, bus_generic_resume), 61354f1d0ceSGarrett Wollman 61454f1d0ceSGarrett Wollman { 0, 0 } 61554f1d0ceSGarrett Wollman }; 61654f1d0ceSGarrett Wollman 617398dbb11SPeter Wemm static driver_t fpupnp_driver = { 618398dbb11SPeter Wemm "fpupnp", 619398dbb11SPeter Wemm fpupnp_methods, 62054f1d0ceSGarrett Wollman 1, /* no softc */ 62154f1d0ceSGarrett Wollman }; 62254f1d0ceSGarrett Wollman 623398dbb11SPeter Wemm static devclass_t fpupnp_devclass; 62454f1d0ceSGarrett Wollman 625398dbb11SPeter Wemm DRIVER_MODULE(fpupnp, acpi, fpupnp_driver, fpupnp_devclass, 0, 0); 626586079ccSBruce Evans #endif /* DEV_ISA */ 6276cf9a08dSKonstantin Belousov 6286cf9a08dSKonstantin Belousov int 6296cf9a08dSKonstantin Belousov fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags) 6306cf9a08dSKonstantin Belousov { 6316cf9a08dSKonstantin Belousov struct pcb *pcb; 6326cf9a08dSKonstantin Belousov 6336cf9a08dSKonstantin Belousov pcb = td->td_pcb; 6346cf9a08dSKonstantin Belousov KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save == &pcb->pcb_user_save, 6356cf9a08dSKonstantin Belousov ("mangled pcb_save")); 6366cf9a08dSKonstantin Belousov ctx->flags = 0; 6376cf9a08dSKonstantin Belousov if ((pcb->pcb_flags & PCB_FPUINITDONE) != 0) 6386cf9a08dSKonstantin Belousov ctx->flags |= FPU_KERN_CTX_FPUINITDONE; 6396cf9a08dSKonstantin Belousov fpuexit(td); 6406cf9a08dSKonstantin Belousov ctx->prev = pcb->pcb_save; 6416cf9a08dSKonstantin Belousov pcb->pcb_save = &ctx->hwstate; 6426cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_KERNFPU; 6436cf9a08dSKonstantin Belousov pcb->pcb_flags &= ~PCB_FPUINITDONE; 6446cf9a08dSKonstantin Belousov return (0); 6456cf9a08dSKonstantin Belousov } 6466cf9a08dSKonstantin Belousov 6476cf9a08dSKonstantin Belousov int 6486cf9a08dSKonstantin Belousov fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx) 6496cf9a08dSKonstantin Belousov { 6506cf9a08dSKonstantin Belousov struct pcb *pcb; 6516cf9a08dSKonstantin Belousov 6526cf9a08dSKonstantin Belousov pcb = td->td_pcb; 65399753495SKonstantin Belousov critical_enter(); 6546cf9a08dSKonstantin Belousov if (curthread == PCPU_GET(fpcurthread)) 6556cf9a08dSKonstantin Belousov fpudrop(); 65699753495SKonstantin Belousov critical_exit(); 6576cf9a08dSKonstantin Belousov pcb->pcb_save = ctx->prev; 6586cf9a08dSKonstantin Belousov if (pcb->pcb_save == &pcb->pcb_user_save) { 6596cf9a08dSKonstantin Belousov if ((pcb->pcb_flags & PCB_USERFPUINITDONE) != 0) 6606cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_FPUINITDONE; 6616cf9a08dSKonstantin Belousov else 6626cf9a08dSKonstantin Belousov pcb->pcb_flags &= ~PCB_FPUINITDONE; 6636cf9a08dSKonstantin Belousov pcb->pcb_flags &= ~PCB_KERNFPU; 6646cf9a08dSKonstantin Belousov } else { 6656cf9a08dSKonstantin Belousov if ((ctx->flags & FPU_KERN_CTX_FPUINITDONE) != 0) 6666cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_FPUINITDONE; 6676cf9a08dSKonstantin Belousov else 6686cf9a08dSKonstantin Belousov pcb->pcb_flags &= ~PCB_FPUINITDONE; 6696cf9a08dSKonstantin Belousov KASSERT(!PCB_USER_FPU(pcb), ("unpaired fpu_kern_leave")); 6706cf9a08dSKonstantin Belousov } 6716cf9a08dSKonstantin Belousov return (0); 6726cf9a08dSKonstantin Belousov } 6736cf9a08dSKonstantin Belousov 6746cf9a08dSKonstantin Belousov int 6756cf9a08dSKonstantin Belousov fpu_kern_thread(u_int flags) 6766cf9a08dSKonstantin Belousov { 6776cf9a08dSKonstantin Belousov struct pcb *pcb; 6786cf9a08dSKonstantin Belousov 6796cf9a08dSKonstantin Belousov pcb = PCPU_GET(curpcb); 6806cf9a08dSKonstantin Belousov KASSERT((curthread->td_pflags & TDP_KTHREAD) != 0, 6816cf9a08dSKonstantin Belousov ("Only kthread may use fpu_kern_thread")); 6826cf9a08dSKonstantin Belousov KASSERT(pcb->pcb_save == &pcb->pcb_user_save, ("mangled pcb_save")); 6836cf9a08dSKonstantin Belousov KASSERT(PCB_USER_FPU(pcb), ("recursive call")); 6846cf9a08dSKonstantin Belousov 6856cf9a08dSKonstantin Belousov pcb->pcb_flags |= PCB_KERNFPU; 6866cf9a08dSKonstantin Belousov return (0); 6876cf9a08dSKonstantin Belousov } 6886cf9a08dSKonstantin Belousov 6896cf9a08dSKonstantin Belousov int 6906cf9a08dSKonstantin Belousov is_fpu_kern_thread(u_int flags) 6916cf9a08dSKonstantin Belousov { 6926cf9a08dSKonstantin Belousov 6936cf9a08dSKonstantin Belousov if ((curthread->td_pflags & TDP_KTHREAD) == 0) 6946cf9a08dSKonstantin Belousov return (0); 6956cf9a08dSKonstantin Belousov return ((PCPU_GET(curpcb)->pcb_flags & PCB_KERNFPU) != 0); 6966cf9a08dSKonstantin Belousov } 697