1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2018, Joyent, Inc.
25 */
26
27 /*
28 * Floating point configuration.
29 */
30
31 #include <sys/types.h>
32 #include <sys/regset.h>
33 #include <sys/privregs.h>
34 #include <sys/x86_archext.h>
35 #include <sys/archsystm.h>
36 #include <sys/fp.h>
37 #include <sys/cmn_err.h>
38 #include <sys/exec.h>
39
40 #define XMM_ALIGN 16
41
42 /*
43 * See section 10.5.1 in the Intel 64 and IA-32 Architectures Software
44 * Developer’s Manual, Volume 1.
45 */
46 #define FXSAVE_ALIGN 16
47
48 /*
49 * See section 13.4 in the Intel 64 and IA-32 Architectures Software
50 * Developer’s Manual, Volume 1.
51 */
52 #define XSAVE_ALIGN 64
53
54 /*
55 * If fpu_exists is non-zero, fpu_probe will attempt to use any
56 * hardware FPU (subject to other constraints, see below). If
57 * fpu_exists is zero, fpu_probe will report that there is no
58 * FPU even if there is one.
59 */
60 int fpu_exists = 1;
61
62 int fp_kind = FP_387;
63
64 /*
65 * The variable fpu_ignored is provided to allow other code to
66 * determine whether emulation is being done because there is
67 * no FPU or because of an override requested via /etc/system.
68 */
69 int fpu_ignored = 0;
70
71 /*
72 * Used by ppcopy and ppzero to determine whether or not to use the
73 * SSE-based pagecopy and pagezero routines
74 */
75 int use_sse_pagecopy = 0;
76 int use_sse_pagezero = 0;
77 int use_sse_copy = 0;
78
79 #if defined(__xpv)
80
81 /*
82 * Use of SSE or otherwise is forcibly configured for us by the hypervisor.
83 */
84
85 #define ENABLE_SSE()
86 #define DISABLE_SSE()
87
88 #else /* __xpv */
89
90 #define ENABLE_SSE() setcr4(CR4_ENABLE_SSE_FLAGS(getcr4()))
91 #define DISABLE_SSE() setcr4(CR4_DISABLE_SSE_FLAGS(getcr4()))
92
93 #endif /* __xpv */
94
95 /*
96 * Try and figure out what kind of FP capabilities we have, and
97 * set up the control registers accordingly.
98 */
99 void
fpu_probe(void)100 fpu_probe(void)
101 {
102 if (fpu_initial_probe() != 0)
103 goto nofpu;
104
105 if (fpu_exists == 0) {
106 fpu_ignored = 1;
107 goto nofpu;
108 }
109
110 #ifndef __xpv
111 /*
112 * Check and see if the fpu is present by looking
113 * at the "extension type" bit. (While this used to
114 * indicate a 387DX coprocessor in days gone by,
115 * it's forced on by modern implementations for
116 * compatibility.)
117 */
118 if ((getcr0() & CR0_ET) == 0)
119 goto nofpu;
120 #endif
121
122 /* Use the more complex exception clearing code if necessary */
123 if (cpuid_need_fp_excp_handling())
124 fpsave_ctxt = fpxsave_excp_clr_ctxt;
125
126 /*
127 * SSE and SSE2 are required for the 64-bit ABI.
128 *
129 * If they're not present, we can in principal run
130 * 32-bit userland, though 64-bit processes will be hosed.
131 *
132 * (Perhaps we should complain more about this case!)
133 */
134 if (is_x86_feature(x86_featureset, X86FSET_SSE) &&
135 is_x86_feature(x86_featureset, X86FSET_SSE2)) {
136 fp_kind |= __FP_SSE;
137 ENABLE_SSE();
138
139 if (is_x86_feature(x86_featureset, X86FSET_AVX)) {
140 ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE));
141 fp_kind |= __FP_AVX;
142 }
143
144 if (is_x86_feature(x86_featureset, X86FSET_XSAVE)) {
145 fp_save_mech = FP_XSAVE;
146 fp_elf = AT_386_FPINFO_XSAVE;
147 if (is_x86_feature(x86_featureset, X86FSET_XSAVEOPT)) {
148 /*
149 * Use the more complex exception
150 * clearing code if necessary.
151 */
152 if (cpuid_need_fp_excp_handling()) {
153 fpsave_ctxt = xsaveopt_excp_clr_ctxt;
154 fp_elf = AT_386_FPINFO_XSAVE_AMD;
155 } else {
156 fpsave_ctxt = xsaveopt_ctxt;
157 }
158 xsavep = xsaveopt;
159 } else {
160 /*
161 * Use the more complex exception
162 * clearing code if necessary.
163 */
164 if (cpuid_need_fp_excp_handling()) {
165 fpsave_ctxt = xsave_excp_clr_ctxt;
166 fp_elf = AT_386_FPINFO_XSAVE_AMD;
167 } else {
168 fpsave_ctxt = xsave_ctxt;
169 }
170 }
171 fprestore_ctxt = xrestore_ctxt;
172 fpsave_cachep = kmem_cache_create("xsave_cache",
173 cpuid_get_xsave_size(), XSAVE_ALIGN,
174 NULL, NULL, NULL, NULL, NULL, 0);
175 } else {
176 /* fp_save_mech defaults to FP_FXSAVE */
177 fpsave_cachep = kmem_cache_create("fxsave_cache",
178 sizeof (struct fxsave_state), FXSAVE_ALIGN,
179 NULL, NULL, NULL, NULL, NULL, 0);
180 fp_elf = AT_386_FPINFO_FXSAVE;
181 }
182 }
183
184 if (is_x86_feature(x86_featureset, X86FSET_SSE2)) {
185 use_sse_pagecopy = use_sse_pagezero = use_sse_copy = 1;
186 }
187
188 if (fp_kind & __FP_SSE) {
189 struct fxsave_state *fx;
190 uint8_t fxsave_state[sizeof (struct fxsave_state) + XMM_ALIGN];
191
192 /*
193 * Extract the mxcsr mask from our first fxsave
194 */
195 fx = (void *)(((uintptr_t)(&fxsave_state[0]) +
196 XMM_ALIGN) & ~(XMM_ALIGN - 1ul));
197
198 fx->fx_mxcsr_mask = 0;
199 fxsave_insn(fx);
200 if (fx->fx_mxcsr_mask != 0) {
201 /*
202 * Override default mask initialized in fpu.c
203 */
204 sse_mxcsr_mask = fx->fx_mxcsr_mask;
205 }
206 }
207
208 setcr0(CR0_ENABLE_FPU_FLAGS(getcr0()));
209 return;
210
211 /*
212 * No FPU hardware present
213 */
214 nofpu:
215 setcr0(CR0_DISABLE_FPU_FLAGS(getcr0()));
216 DISABLE_SSE();
217 fp_kind = FP_NO;
218 fpu_exists = 0;
219 }
220