1 /* $OpenBSD: fpu.c,v 1.44 2023/05/22 00:39:57 guenther Exp $ */
2 /* $NetBSD: fpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */
3
4 /*-
5 * Copyright (c) 1994, 1995, 1998 Charles M. Hannum. All rights reserved.
6 * Copyright (c) 1990 William Jolitz.
7 * Copyright (c) 1991 The Regents of the University of California.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/proc.h>
38 #include <sys/user.h>
39
40 #include <machine/cpu.h>
41 #include <machine/intr.h>
42 #include <machine/cpufunc.h>
43 #include <machine/pcb.h>
44 #include <machine/trap.h>
45 #include <machine/specialreg.h>
46 #include <machine/fpu.h>
47
48
49 /*
50 * The mask of enabled XSAVE features.
51 */
52 uint64_t xsave_mask;
53
54 static int x86fpflags_to_siginfo(u_int32_t);
55
56 /*
57 * Size of the area needed to save the FPU state and other
58 * XSAVE-supported state components.
59 */
60 size_t fpu_save_len = sizeof(struct fxsave64);
61
62 /*
63 * The mxcsr_mask for this host, taken from fxsave() on the primary CPU
64 */
65 uint32_t fpu_mxcsr_mask;
66
67 /*
68 * Init the FPU.
69 */
70 void
fpuinit(struct cpu_info * ci)71 fpuinit(struct cpu_info *ci)
72 {
73 fninit();
74 if (fpu_mxcsr_mask == 0) {
75 struct fxsave64 fx __attribute__((aligned(16)));
76
77 bzero(&fx, sizeof(fx));
78 fxsave(&fx);
79 if (fx.fx_mxcsr_mask)
80 fpu_mxcsr_mask = fx.fx_mxcsr_mask;
81 else
82 fpu_mxcsr_mask = __INITIAL_MXCSR_MASK__;
83 }
84 }
85
86 /*
87 * Record the FPU state and reinitialize it all except for the control word.
88 * Returns the code to include in an SIGFPE.
89 *
90 * Reinitializing the state allows naive SIGFPE handlers to longjmp without
91 * doing any fixups.
92 */
93 int
fputrap(int type)94 fputrap(int type)
95 {
96 struct cpu_info *ci = curcpu();
97 struct proc *p = curproc;
98 struct savefpu *sfp = &p->p_addr->u_pcb.pcb_savefpu;
99 u_int32_t mxcsr, statbits;
100 u_int16_t cw;
101
102 KASSERT(ci->ci_pflags & CPUPF_USERXSTATE);
103 ci->ci_pflags &= ~CPUPF_USERXSTATE;
104 fpusavereset(sfp);
105
106 if (type == T_XMM) {
107 mxcsr = sfp->fp_fxsave.fx_mxcsr;
108 statbits = mxcsr;
109 mxcsr &= ~0x3f;
110 ldmxcsr(&mxcsr);
111 } else {
112 fninit();
113 fwait();
114 cw = sfp->fp_fxsave.fx_fcw;
115 fldcw(&cw);
116 fwait();
117 statbits = sfp->fp_fxsave.fx_fsw;
118 }
119 return x86fpflags_to_siginfo(statbits);
120 }
121
122 static int
x86fpflags_to_siginfo(u_int32_t flags)123 x86fpflags_to_siginfo(u_int32_t flags)
124 {
125 int i;
126 static int x86fp_siginfo_table[] = {
127 FPE_FLTINV, /* bit 0 - invalid operation */
128 FPE_FLTRES, /* bit 1 - denormal operand */
129 FPE_FLTDIV, /* bit 2 - divide by zero */
130 FPE_FLTOVF, /* bit 3 - fp overflow */
131 FPE_FLTUND, /* bit 4 - fp underflow */
132 FPE_FLTRES, /* bit 5 - fp precision */
133 FPE_FLTINV, /* bit 6 - stack fault */
134 };
135
136 for (i = 0; i < nitems(x86fp_siginfo_table); i++) {
137 if (flags & (1 << i))
138 return (x86fp_siginfo_table[i]);
139 }
140 /* punt if flags not set */
141 return (FPE_FLTINV);
142 }
143
144 void
fpu_kernel_enter(void)145 fpu_kernel_enter(void)
146 {
147 struct cpu_info *ci = curcpu();
148
149 /* save curproc's FPU state if we haven't already */
150 if (ci->ci_pflags & CPUPF_USERXSTATE) {
151 ci->ci_pflags &= ~CPUPF_USERXSTATE;
152 fpusavereset(&curproc->p_addr->u_pcb.pcb_savefpu);
153 } else {
154 fpureset();
155 }
156 }
157
158 void
fpu_kernel_exit(void)159 fpu_kernel_exit(void)
160 {
161 /* make sure we don't leave anything in the registers */
162 fpureset();
163 }
164