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 */ 25 26 /* 27 * Floating point configuration. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/regset.h> 32 #include <sys/privregs.h> 33 #include <sys/x86_archext.h> 34 #include <sys/archsystm.h> 35 #include <sys/fp.h> 36 #include <sys/cmn_err.h> 37 38 #define XMM_ALIGN 16 39 40 /* 41 * If fpu_exists is non-zero, fpu_probe will attempt to use any 42 * hardware FPU (subject to other constraints, see below). If 43 * fpu_exists is zero, fpu_probe will report that there is no 44 * FPU even if there is one. 45 */ 46 int fpu_exists = 1; 47 48 int fp_kind = FP_387; 49 50 /* 51 * The variable fpu_ignored is provided to allow other code to 52 * determine whether emulation is being done because there is 53 * no FPU or because of an override requested via /etc/system. 54 */ 55 int fpu_ignored = 0; 56 57 /* 58 * Used by ppcopy and ppzero to determine whether or not to use the 59 * SSE-based pagecopy and pagezero routines 60 */ 61 int use_sse_pagecopy = 0; 62 int use_sse_pagezero = 0; 63 int use_sse_copy = 0; 64 65 #if defined(__i386) 66 67 /* 68 * The variable fpu_pentium_fdivbug is provided to allow other code to 69 * determine whether the system contains a Pentium with the FDIV problem. 70 */ 71 int fpu_pentium_fdivbug = 0; 72 73 #endif 74 75 #if defined(__xpv) 76 77 /* 78 * Use of SSE or otherwise is forcibly configured for us by the hypervisor. 79 */ 80 81 #define ENABLE_SSE() 82 #define DISABLE_SSE() 83 84 #else /* __xpv */ 85 86 #define ENABLE_SSE() setcr4(CR4_ENABLE_SSE_FLAGS(getcr4())) 87 #define DISABLE_SSE() setcr4(CR4_DISABLE_SSE_FLAGS(getcr4())) 88 89 #endif /* __xpv */ 90 91 /* 92 * Try and figure out what kind of FP capabilities we have, and 93 * set up the control registers accordingly. 94 */ 95 void 96 fpu_probe(void) 97 { 98 do { 99 if (fpu_initial_probe() != 0) 100 continue; 101 102 if (fpu_exists == 0) { 103 fpu_ignored = 1; 104 continue; 105 } 106 107 #if defined(__i386) 108 fpu_pentium_fdivbug = fpu_probe_pentium_fdivbug(); 109 /* 110 * The test does some real floating point operations. 111 * Reset it back to previous state. 112 */ 113 (void) fpu_initial_probe(); 114 115 if (fpu_pentium_fdivbug != 0) { 116 fpu_ignored = 1; 117 continue; 118 } 119 #endif 120 121 #ifndef __xpv 122 /* 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.) 128 */ 129 if ((getcr0() & CR0_ET) == 0) 130 continue; 131 #endif 132 133 #if defined(__amd64) 134 /* 135 * SSE and SSE2 are required for the 64-bit ABI. 136 * 137 * If they're not present, we can in principal run 138 * 32-bit userland, though 64-bit processes will be hosed. 139 * 140 * (Perhaps we should complain more about this case!) 141 */ 142 if (is_x86_feature(x86_featureset, X86FSET_SSE) && 143 is_x86_feature(x86_featureset, X86FSET_SSE2)) { 144 fp_kind = __FP_SSE; 145 ENABLE_SSE(); 146 } 147 #elif defined(__i386) 148 /* 149 * SSE and SSE2 are both optional, and we patch kernel 150 * code to exploit it when present. 151 */ 152 if (is_x86_feature(x86_featureset, X86FSET_SSE)) { 153 fp_kind = __FP_SSE; 154 fpsave_ctxt = fpxsave_ctxt; 155 patch_sse(); 156 if (is_x86_feature(x86_featureset, X86FSET_SSE2)) 157 patch_sse2(); 158 ENABLE_SSE(); 159 } else { 160 remove_x86_feature(x86_featureset, X86FSET_SSE2); 161 /* 162 * (Just in case the BIOS decided we wanted SSE 163 * enabled when we didn't. See 4965674.) 164 */ 165 DISABLE_SSE(); 166 } 167 #endif 168 if (is_x86_feature(x86_featureset, X86FSET_SSE2)) { 169 use_sse_pagecopy = use_sse_pagezero = use_sse_copy = 1; 170 } 171 172 if (fp_kind == __FP_SSE) { 173 struct fxsave_state *fx; 174 uint8_t fxsave_state[sizeof (struct fxsave_state) + 175 XMM_ALIGN]; 176 177 /* 178 * Extract the mxcsr mask from our first fxsave 179 */ 180 fx = (void *)(((uintptr_t)(&fxsave_state[0]) + 181 XMM_ALIGN) & ~(XMM_ALIGN - 1ul)); 182 183 fx->fx_mxcsr_mask = 0; 184 fxsave_insn(fx); 185 if (fx->fx_mxcsr_mask != 0) { 186 /* 187 * Override default mask initialized in fpu.c 188 */ 189 sse_mxcsr_mask = fx->fx_mxcsr_mask; 190 } 191 } 192 193 setcr0(CR0_ENABLE_FPU_FLAGS(getcr0())); 194 return; 195 /*CONSTANTCONDITION*/ 196 } while (0); 197 198 /* 199 * No FPU hardware present 200 */ 201 setcr0(CR0_DISABLE_FPU_FLAGS(getcr0())); 202 DISABLE_SSE(); 203 fp_kind = FP_NO; 204 fpu_exists = 0; 205 } 206