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 79 #define ENABLE_SSE() setcr4(CR4_ENABLE_SSE_FLAGS(getcr4())) 80 #define DISABLE_SSE() setcr4(CR4_DISABLE_SSE_FLAGS(getcr4())) 81 82 /* 83 * Try and figure out what kind of FP capabilities we have, and 84 * set up the control registers accordingly. 85 */ 86 void 87 fpu_probe(void) 88 { 89 do { 90 if (fpu_initial_probe() != 0) 91 continue; 92 93 if (fpu_exists == 0) { 94 fpu_ignored = 1; 95 continue; 96 } 97 98 #if defined(__i386) 99 fpu_pentium_fdivbug = fpu_probe_pentium_fdivbug(); 100 /* 101 * The test does some real floating point operations. 102 * Reset it back to previous state. 103 */ 104 (void) fpu_initial_probe(); 105 106 if (fpu_pentium_fdivbug != 0) { 107 fpu_ignored = 1; 108 continue; 109 } 110 #endif 111 112 /* 113 * Check and see if the fpu is present by looking 114 * at the "extension type" bit. (While this used to 115 * indicate a 387DX coprocessor in days gone by, 116 * it's forced on by modern implementations for 117 * compatibility.) 118 */ 119 if ((getcr0() & CR0_ET) == 0) 120 continue; 121 122 #if defined(__amd64) 123 /* 124 * SSE and SSE2 are required for the 64-bit ABI. 125 * 126 * If they're not present, we can in principal run 127 * 32-bit userland, though 64-bit processes will be hosed. 128 * 129 * (Perhaps we should complain more about this case!) 130 */ 131 if ((x86_feature & X86_SSE|X86_SSE2) == (X86_SSE|X86_SSE2)) { 132 fp_kind = __FP_SSE; 133 ENABLE_SSE(); 134 } 135 #elif defined(__i386) 136 /* 137 * SSE and SSE2 are both optional, and we patch kernel 138 * code to exploit it when present. 139 */ 140 if (x86_feature & X86_SSE) { 141 fp_kind = __FP_SSE; 142 fpsave_ctxt = fpxsave_ctxt; 143 patch_sse(); 144 if (x86_feature & X86_SSE2) 145 patch_sse2(); 146 ENABLE_SSE(); 147 } else { 148 x86_feature &= ~X86_SSE2; 149 /* 150 * (Just in case the BIOS decided we wanted SSE 151 * enabled when we didn't. See 4965674.) 152 */ 153 DISABLE_SSE(); 154 } 155 #endif 156 if (x86_feature & X86_SSE2) { 157 use_sse_pagecopy = use_sse_pagezero = use_sse_copy = 1; 158 } 159 160 if (fp_kind == __FP_SSE) { 161 struct fxsave_state *fx; 162 uint8_t fxsave_state[sizeof (struct fxsave_state) + 163 XMM_ALIGN]; 164 165 /* 166 * Extract the mxcsr mask from our first fxsave 167 */ 168 fx = (void *)(((uintptr_t)(&fxsave_state[0]) + 169 XMM_ALIGN) & ~(XMM_ALIGN - 1ul)); 170 171 fx->fx_mxcsr_mask = 0; 172 fxsave_insn(fx); 173 if (fx->fx_mxcsr_mask != 0) { 174 /* 175 * Override default mask initialized in fpu.c 176 */ 177 sse_mxcsr_mask = fx->fx_mxcsr_mask; 178 } 179 } 180 181 setcr0(CR0_ENABLE_FPU_FLAGS(getcr0())); 182 return; 183 /*CONSTANTCONDITION*/ 184 } while (0); 185 186 /* 187 * No FPU hardware present 188 */ 189 setcr0(CR0_DISABLE_FPU_FLAGS(getcr0())); 190 DISABLE_SSE(); 191 fp_kind = FP_NO; 192 fpu_exists = 0; 193 } 194