common_x86.c revision ab9e273c75e2d752e5027f7790480120c672ce01
1/* $Id: common_x86.c,v 1.9 2000/12/07 02:36:38 gareth Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.5 6 * 7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28/* 29 * Check CPU capabilities & initialize optimized funtions for this particular 30 * processor. 31 * 32 * Written by Holger Waechtler <holger@akaflieg.extern.tu-berlin.de> 33 * Changed by Andre Werthmann <wertmann@cs.uni-potsdam.de> for using the 34 * new Katmai functions. 35 */ 36 37#include <stdlib.h> 38#include <stdio.h> 39#if defined(USE_KATMAI_ASM) && defined(__linux__) && defined(_POSIX_SOURCE) 40#include <signal.h> 41#endif 42 43#include "context.h" 44#include "common_x86_asm.h" 45 46 47int gl_x86_cpu_features = 0; 48 49/* No reason for this to be public. 50 */ 51extern int gl_identify_x86_cpu_features( void ); 52 53 54static void message( const char *msg ) 55{ 56 GLboolean debug; 57#ifdef DEBUG 58 debug = GL_TRUE; 59#else 60 if ( getenv( "MESA_DEBUG" ) ) { 61 debug = GL_TRUE; 62 } else { 63 debug = GL_FALSE; 64 } 65#endif 66 if ( debug ) { 67 fprintf( stderr, "%s", msg ); 68 } 69} 70 71#if defined(USE_KATMAI_ASM) 72/* 73 * We must verify that the Streaming SIMD Extensions are truly supported 74 * on this processor before we go ahead and hook out the optimized code. 75 * Unfortunately, the CPUID bit isn't enough, as the OS must set the 76 * OSFXSR bit in CR4 if it supports the extended FPU save and restore 77 * required to use SSE. Unfortunately, we can't just go ahead and read 78 * this register, as only the kernel can do that. Similarly, we must 79 * verify that the OSXMMEXCPT bit in CR4 has been set by the OS, 80 * signifying that it supports unmasked SIMD FPU exceptions. If we take 81 * an unmasked exception and the OS doesn't correctly support them, the 82 * best we'll get is a SIGILL and the worst we'll get is an infinite 83 * loop in the signal delivery from the kernel as we can't interact with 84 * the SIMD FPU state to clear the exception bits. Either way, this is 85 * not good. 86 */ 87 88extern void gl_test_os_katmai_support( void ); 89extern void gl_test_os_katmai_exception_support( void ); 90 91#if defined(__linux__) && defined(_POSIX_SOURCE) 92static void sigill_handler( int signal, struct sigcontext sc ) 93{ 94 message( "SIGILL, " ); 95 96 /* Both the "xorps %%xmm0,%%xmm0" and "divps %xmm0,%%xmm1" 97 * instructions are 3 bytes long. We must increment the instruction 98 * pointer manually to avoid repeated execution of the offending 99 * instruction. 100 * 101 * If the SIGILL is caused by a divide-by-zero when unmasked 102 * exceptions aren't supported, the SIMD FPU status and control 103 * word will be restored at the end of the test, so we don't need 104 * to worry about doing it here. Besides, we may not be able to... 105 */ 106 sc.eip += 3; 107 108 gl_x86_cpu_features &= ~(X86_FEATURE_XMM); 109} 110 111static void sigfpe_handler( int signal, struct sigcontext sc ) 112{ 113 message( "SIGFPE, " ); 114 115 if ( sc.fpstate->magic != 0xffff ) { 116 /* Our signal context has the extended FPU state, so reset the 117 * divide-by-zero exception mask and clear the divide-by-zero 118 * exception bit. 119 */ 120 sc.fpstate->mxcsr |= 0x00000200; 121 sc.fpstate->mxcsr &= 0xfffffffb; 122 } else { 123 /* If we ever get here, we're completely hosed. 124 */ 125 message( "\n\n" ); 126 gl_problem( NULL, "SSE enabling test failed badly!" ); 127 } 128} 129#endif /* __linux__ && _POSIX_SOURCE */ 130 131/* If we're running on a processor that can do SSE, let's see if we 132 * are allowed to or not. This will catch 2.4.0 or later kernels that 133 * haven't been configured for a Pentium III but are running on one, 134 * and RedHat patched 2.2 kernels that have broken exception handling 135 * support for user space apps that do SSE. 136 * 137 * GH: Isn't this just awful? 138 */ 139static void check_os_katmai_support( void ) 140{ 141#if defined(__linux__) 142#if defined(_POSIX_SOURCE) 143 struct sigaction saved_sigill; 144 struct sigaction saved_sigfpe; 145 146 /* Save the original signal handlers. 147 */ 148 sigaction( SIGILL, NULL, &saved_sigill ); 149 sigaction( SIGFPE, NULL, &saved_sigfpe ); 150 151 signal( SIGILL, (void (*)(int))sigill_handler ); 152 signal( SIGFPE, (void (*)(int))sigfpe_handler ); 153 154 /* Emulate test for OSFXSR in CR4. The OS will set this bit if it 155 * supports the extended FPU save and restore required for SSE. If 156 * we execute an SSE instruction on a PIII and get a SIGILL, the OS 157 * doesn't support Streaming SIMD Exceptions, even if the processor 158 * does. 159 */ 160 if ( cpu_has_xmm ) { 161 message( "Testing OS support for SSE... " ); 162 163 gl_test_os_katmai_support(); 164 165 if ( cpu_has_xmm ) { 166 message( "yes.\n" ); 167 } else { 168 message( "no!\n" ); 169 } 170 } 171 172 /* Emulate test for OSXMMEXCPT in CR4. The OS will set this bit if 173 * it supports unmasked SIMD FPU exceptions. If we unmask the 174 * exceptions, do a SIMD divide-by-zero and get a SIGILL, the OS 175 * doesn't support unmasked SIMD FPU exceptions. If we get a SIGFPE 176 * as expected, we're okay but we need to clean up after it. 177 * 178 * Are we being too stringent in our requirement that the OS support 179 * unmasked exceptions? Certain RedHat 2.2 kernels enable SSE by 180 * setting CR4.OSFXSR but don't support unmasked exceptions. Win98 181 * doesn't even support them. We at least know the user-space SSE 182 * support is good in kernels that do support unmasked exceptions, 183 * and therefore to be safe I'm going to leave this test in here. 184 */ 185 if ( cpu_has_xmm ) { 186 message( "Testing OS support for SSE unmasked exceptions... " ); 187 188 gl_test_os_katmai_exception_support(); 189 190 if ( cpu_has_xmm ) { 191 message( "yes.\n" ); 192 } else { 193 message( "no!\n" ); 194 } 195 } 196 197 /* Restore the original signal handlers. 198 */ 199 sigaction( SIGILL, &saved_sigill, NULL ); 200 sigaction( SIGFPE, &saved_sigfpe, NULL ); 201 202 /* If we've gotten to here and the XMM CPUID bit is still set, we're 203 * safe to go ahead and hook out the SSE code throughout Mesa. 204 */ 205 if ( cpu_has_xmm ) { 206 message( "Tests of OS support for SSE passed.\n" ); 207 } else { 208 message( "Tests of OS support for SSE failed!\n" ); 209 } 210#else 211 /* We can't use POSIX signal handling to test the availability of 212 * SSE, so we disable it by default. 213 */ 214 message( "Cannot test OS support for SSE, disabling to be safe.\n" ); 215 gl_x86_cpu_features &= ~(X86_FEATURE_XMM); 216#endif /* _POSIX_SOURCE */ 217#else 218 /* Do nothing on non-Linux platforms for now. 219 */ 220 message( "Not testing OS support for SSE, leaving enabled.\n" ); 221#endif /* __linux__ */ 222} 223 224#endif /* USE_KATMAI_ASM */ 225 226 227void gl_init_all_x86_transform_asm( void ) 228{ 229#ifdef USE_X86_ASM 230 gl_x86_cpu_features = gl_identify_x86_cpu_features(); 231 232 if ( getenv( "MESA_NO_ASM" ) ) { 233 gl_x86_cpu_features = 0; 234 } 235 236 if ( gl_x86_cpu_features ) { 237 gl_init_x86_transform_asm(); 238 } 239 240#ifdef USE_MMX_ASM 241 if ( cpu_has_mmx ) { 242 if ( getenv( "MESA_NO_MMX" ) == 0 ) { 243 message( "MMX cpu detected.\n" ); 244 } else { 245 gl_x86_cpu_features &= ~(X86_FEATURE_MMX); 246 } 247 } 248#endif 249 250#ifdef USE_3DNOW_ASM 251 if ( cpu_has_3dnow ) { 252 if ( getenv( "MESA_NO_3DNOW" ) == 0 ) { 253 message( "3DNow! cpu detected.\n" ); 254 gl_init_3dnow_transform_asm(); 255 } else { 256 gl_x86_cpu_features &= ~(X86_FEATURE_3DNOW); 257 } 258 } 259#endif 260 261#ifdef USE_KATMAI_ASM 262 if ( cpu_has_xmm && getenv( "MESA_FORCE_KATMAI" ) == 0 ) { 263 check_os_katmai_support(); 264 } 265 if ( cpu_has_xmm ) { 266 if ( getenv( "MESA_NO_KATMAI" ) == 0 ) { 267 message( "Katmai cpu detected.\n" ); 268 gl_init_katmai_transform_asm(); 269 } else { 270 gl_x86_cpu_features &= ~(X86_FEATURE_XMM); 271 } 272 } 273#endif 274#endif 275} 276 277/* Note: the above function must be called before this one, so that 278 * gl_x86_cpu_features gets correctly initialized. 279 */ 280void gl_init_all_x86_vertex_asm( void ) 281{ 282#ifdef USE_X86_ASM 283 if ( gl_x86_cpu_features ) { 284 gl_init_x86_vertex_asm(); 285 } 286 287#ifdef USE_3DNOW_ASM 288 if ( cpu_has_3dnow && getenv( "MESA_NO_3DNOW" ) == 0 ) { 289 gl_init_3dnow_vertex_asm(); 290 } 291#endif 292 293#ifdef USE_KATMAI_ASM 294 if ( cpu_has_xmm && getenv( "MESA_NO_KATMAI" ) == 0 ) { 295 gl_init_katmai_vertex_asm(); 296 } 297#endif 298#endif 299} 300