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