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 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