9596 Initial xsave xstate_bv should not include all features
[unleashed.git] / usr / src / uts / i86pc / os / fpu_subr.c
blob3e027269fb6a4279c27305ac783e54514608646d
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2018, Joyent, Inc.
28 * Floating point configuration.
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>
40 #define XMM_ALIGN 16
43 * See section 10.5.1 in the Intel 64 and IA-32 Architectures Software
44 * Developer’s Manual, Volume 1.
46 #define FXSAVE_ALIGN 16
49 * See section 13.4 in the Intel 64 and IA-32 Architectures Software
50 * Developer’s Manual, Volume 1.
52 #define XSAVE_ALIGN 64
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.
60 int fpu_exists = 1;
62 int fp_kind = FP_387;
65 * The kind of FPU we advertise to rtld so it knows what to do on context
66 * switch.
68 int fp_elf = AT_386_FPINFO_FXSAVE;
71 * Mechanism to save FPU state.
73 int fp_save_mech = FP_FXSAVE;
76 * The variable fpu_ignored is provided to allow other code to
77 * determine whether emulation is being done because there is
78 * no FPU or because of an override requested via /etc/system.
80 int fpu_ignored = 0;
83 * Used by ppcopy and ppzero to determine whether or not to use the
84 * SSE-based pagecopy and pagezero routines
86 int use_sse_pagecopy = 0;
87 int use_sse_pagezero = 0;
88 int use_sse_copy = 0;
90 #if defined(__xpv)
93 * Use of SSE or otherwise is forcibly configured for us by the hypervisor.
96 #define ENABLE_SSE()
97 #define DISABLE_SSE()
99 #else /* __xpv */
101 #define ENABLE_SSE() setcr4(CR4_ENABLE_SSE_FLAGS(getcr4()))
102 #define DISABLE_SSE() setcr4(CR4_DISABLE_SSE_FLAGS(getcr4()))
104 #endif /* __xpv */
107 * Try and figure out what kind of FP capabilities we have, and
108 * set up the control registers accordingly.
110 void
111 fpu_probe(void)
113 if (fpu_initial_probe() != 0)
114 goto nofpu;
116 if (fpu_exists == 0) {
117 fpu_ignored = 1;
118 goto nofpu;
121 #ifndef __xpv
123 * Check and see if the fpu is present by looking
124 * at the "extension type" bit. (While this used to
125 * indicate a 387DX coprocessor in days gone by,
126 * it's forced on by modern implementations for
127 * compatibility.)
129 if ((getcr0() & CR0_ET) == 0)
130 goto nofpu;
131 #endif
133 /* Use the more complex exception clearing code if necessary */
134 if (cpuid_need_fp_excp_handling())
135 fpsave_ctxt = fpxsave_excp_clr_ctxt;
138 * SSE and SSE2 are required for the 64-bit ABI.
140 * If they're not present, we can in principal run
141 * 32-bit userland, though 64-bit processes will be hosed.
143 * (Perhaps we should complain more about this case!)
145 if (is_x86_feature(x86_featureset, X86FSET_SSE) &&
146 is_x86_feature(x86_featureset, X86FSET_SSE2)) {
147 fp_kind |= __FP_SSE;
148 ENABLE_SSE();
150 if (is_x86_feature(x86_featureset, X86FSET_AVX)) {
151 ASSERT(is_x86_feature(x86_featureset,
152 X86FSET_XSAVE));
153 fp_kind |= __FP_AVX;
156 if (is_x86_feature(x86_featureset, X86FSET_XSAVE)) {
157 fp_save_mech = FP_XSAVE;
158 fp_elf = AT_386_FPINFO_XSAVE;
159 if (is_x86_feature(x86_featureset, X86FSET_XSAVEOPT)) {
161 * Use the more complex exception
162 * clearing code if necessary.
164 if (cpuid_need_fp_excp_handling()) {
165 fpsave_ctxt = xsaveopt_excp_clr_ctxt;
166 fp_elf = AT_386_FPINFO_XSAVE_AMD;
167 } else {
168 fpsave_ctxt = xsaveopt_ctxt;
170 xsavep = xsaveopt;
171 } else {
173 * Use the more complex exception
174 * clearing code if necessary.
176 if (cpuid_need_fp_excp_handling()) {
177 fpsave_ctxt = xsave_excp_clr_ctxt;
178 fp_elf = AT_386_FPINFO_XSAVE_AMD;
179 } else {
180 fpsave_ctxt = xsave_ctxt;
183 patch_xsave();
184 fpsave_cachep = kmem_cache_create("xsave_cache",
185 cpuid_get_xsave_size(), XSAVE_ALIGN,
186 NULL, NULL, NULL, NULL, NULL, 0);
187 } else {
188 /* fp_save_mech defaults to FP_FXSAVE */
189 fpsave_cachep = kmem_cache_create("fxsave_cache",
190 sizeof (struct fxsave_state), FXSAVE_ALIGN,
191 NULL, NULL, NULL, NULL, NULL, 0);
192 fp_elf = AT_386_FPINFO_FXSAVE;
196 if (is_x86_feature(x86_featureset, X86FSET_SSE2)) {
197 use_sse_pagecopy = use_sse_pagezero = use_sse_copy = 1;
200 if (fp_kind & __FP_SSE) {
201 struct fxsave_state *fx;
202 uint8_t fxsave_state[sizeof (struct fxsave_state) + XMM_ALIGN];
205 * Extract the mxcsr mask from our first fxsave
207 fx = (void *)(((uintptr_t)(&fxsave_state[0]) +
208 XMM_ALIGN) & ~(XMM_ALIGN - 1ul));
210 fx->fx_mxcsr_mask = 0;
211 fxsave_insn(fx);
212 if (fx->fx_mxcsr_mask != 0) {
214 * Override default mask initialized in fpu.c
216 sse_mxcsr_mask = fx->fx_mxcsr_mask;
220 setcr0(CR0_ENABLE_FPU_FLAGS(getcr0()));
221 return;
224 * No FPU hardware present
226 nofpu:
227 setcr0(CR0_DISABLE_FPU_FLAGS(getcr0()));
228 DISABLE_SSE();
229 fp_kind = FP_NO;
230 fpu_exists = 0;
234 * Fill in FPU information that is required by exec.
236 void
237 fpu_auxv_info(int *typep, size_t *lenp)
239 *typep = fp_elf;
240 switch (fp_save_mech) {
241 case FP_FXSAVE:
242 *lenp = sizeof (struct fxsave_state);
243 break;
244 case FP_XSAVE:
245 *lenp = cpuid_get_xsave_size();
246 break;
247 default:
248 *lenp = 0;
249 break;