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]
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>
37 #include <sys/cmn_err.h>
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.
65 * The kind of FPU we advertise to rtld so it knows what to do on context
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.
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;
93 * Use of SSE or otherwise is forcibly configured for us by the hypervisor.
101 #define ENABLE_SSE() setcr4(CR4_ENABLE_SSE_FLAGS(getcr4()))
102 #define DISABLE_SSE() setcr4(CR4_DISABLE_SSE_FLAGS(getcr4()))
107 * Try and figure out what kind of FP capabilities we have, and
108 * set up the control registers accordingly.
113 if (fpu_initial_probe() != 0)
116 if (fpu_exists
== 0) {
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
129 if ((getcr0() & CR0_ET
) == 0)
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
)) {
150 if (is_x86_feature(x86_featureset
, X86FSET_AVX
)) {
151 ASSERT(is_x86_feature(x86_featureset
,
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
;
168 fpsave_ctxt
= xsaveopt_ctxt
;
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
;
180 fpsave_ctxt
= xsave_ctxt
;
184 fpsave_cachep
= kmem_cache_create("xsave_cache",
185 cpuid_get_xsave_size(), XSAVE_ALIGN
,
186 NULL
, NULL
, NULL
, NULL
, NULL
, 0);
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;
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()));
224 * No FPU hardware present
227 setcr0(CR0_DISABLE_FPU_FLAGS(getcr0()));
234 * Fill in FPU information that is required by exec.
237 fpu_auxv_info(int *typep
, size_t *lenp
)
240 switch (fp_save_mech
) {
242 *lenp
= sizeof (struct fxsave_state
);
245 *lenp
= cpuid_get_xsave_size();