00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <vlc/vlc.h>
00030
00031 #ifdef HAVE_SIGNAL_H
00032 # include <signal.h>
00033 # include <setjmp.h>
00034 #endif
00035
00036 #ifdef SYS_DARWIN
00037 #include <sys/sysctl.h>
00038 #endif
00039
00040 #include "vlc_cpu.h"
00041
00042
00043
00044
00045 #ifdef HAVE_SIGNAL_H
00046 static void SigHandler ( int );
00047 #endif
00048
00049
00050
00051
00052 #ifdef HAVE_SIGNAL_H
00053 static jmp_buf env;
00054 static int i_illegal;
00055 #if defined( __i386__ ) || defined( __x86_64__ )
00056 static char *psz_capability;
00057 #endif
00058 #endif
00059
00060
00061
00062
00063
00064
00065 uint32_t CPUCapabilities( void )
00066 {
00067 volatile uint32_t i_capabilities = CPU_CAPABILITY_NONE;
00068
00069 #if defined( SYS_DARWIN )
00070 int selectors[2] = { CTL_HW, HW_VECTORUNIT };
00071 int i_has_altivec = 0;
00072 size_t i_length = sizeof( i_has_altivec );
00073 int i_error = sysctl( selectors, 2, &i_has_altivec, &i_length, NULL, 0);
00074
00075 i_capabilities |= CPU_CAPABILITY_FPU;
00076
00077 if( i_error == 0 && i_has_altivec != 0 )
00078 i_capabilities |= CPU_CAPABILITY_ALTIVEC;
00079
00080 return i_capabilities;
00081
00082 #elif defined( __i386__ ) || defined( __x86_64__ )
00083 volatile unsigned int i_eax, i_ebx, i_ecx, i_edx;
00084 volatile vlc_bool_t b_amd;
00085
00086
00087 # if defined( __x86_64__ )
00088 # define cpuid( reg ) \
00089 asm volatile ( "cpuid\n\t" \
00090 "movl %%ebx,%1\n\t" \
00091 : "=a" ( i_eax ), \
00092 "=b" ( i_ebx ), \
00093 "=c" ( i_ecx ), \
00094 "=d" ( i_edx ) \
00095 : "a" ( reg ) \
00096 : "cc" );
00097 # else
00098 # define cpuid( reg ) \
00099 asm volatile ( "push %%ebx\n\t" \
00100 "cpuid\n\t" \
00101 "movl %%ebx,%1\n\t" \
00102 "pop %%ebx\n\t" \
00103 : "=a" ( i_eax ), \
00104 "=r" ( i_ebx ), \
00105 "=c" ( i_ecx ), \
00106 "=d" ( i_edx ) \
00107 : "a" ( reg ) \
00108 : "cc" );
00109 # endif
00110
00111 # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) \
00112 && defined( HAVE_SIGNAL_H )
00113 void (*pf_sigill) (int) = signal( SIGILL, SigHandler );
00114 # endif
00115
00116 i_capabilities |= CPU_CAPABILITY_FPU;
00117
00118 # if defined( __i386__ )
00119
00120 asm volatile ( "push %%ebx\n\t"
00121 "pushf\n\t"
00122 "pop %%eax\n\t"
00123 "movl %%eax, %%ebx\n\t"
00124 "xorl $0x200000, %%eax\n\t"
00125 "push %%eax\n\t"
00126 "popf\n\t"
00127 "pushf\n\t"
00128 "pop %%eax\n\t"
00129 "movl %%ebx,%1\n\t"
00130 "pop %%ebx\n\t"
00131 : "=a" ( i_eax ),
00132 "=r" ( i_ebx )
00133 :
00134 : "cc" );
00135
00136 if( i_eax == i_ebx )
00137 {
00138 # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) \
00139 && defined( HAVE_SIGNAL_H )
00140 signal( SIGILL, pf_sigill );
00141 # endif
00142 return i_capabilities;
00143 }
00144 # else
00145
00146 # endif
00147
00148 i_capabilities |= CPU_CAPABILITY_486;
00149
00150
00151 cpuid( 0x00000000 );
00152
00153 if( !i_eax )
00154 {
00155 # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) \
00156 && defined( HAVE_SIGNAL_H )
00157 signal( SIGILL, pf_sigill );
00158 # endif
00159 return i_capabilities;
00160 }
00161
00162
00163 i_capabilities |= CPU_CAPABILITY_586;
00164
00165
00166 b_amd = ( i_ebx == 0x68747541 ) && ( i_ecx == 0x444d4163 )
00167 && ( i_edx == 0x69746e65 );
00168
00169
00170 cpuid( 0x00000001 );
00171
00172 if( ! (i_edx & 0x00800000) )
00173 {
00174 # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) \
00175 && defined( HAVE_SIGNAL_H )
00176 signal( SIGILL, pf_sigill );
00177 # endif
00178 return i_capabilities;
00179 }
00180
00181 i_capabilities |= CPU_CAPABILITY_MMX;
00182
00183 if( i_edx & 0x02000000 )
00184 {
00185 i_capabilities |= CPU_CAPABILITY_MMXEXT;
00186
00187 # ifdef CAN_COMPILE_SSE
00188
00189 psz_capability = "SSE";
00190 i_illegal = 0;
00191
00192 if( setjmp( env ) == 0 )
00193 {
00194
00195 __asm__ __volatile__ ( "xorps %%xmm0,%%xmm0\n" : : );
00196 }
00197
00198 if( i_illegal == 0 )
00199 {
00200 i_capabilities |= CPU_CAPABILITY_SSE;
00201 }
00202 # endif
00203 }
00204
00205 if( i_edx & 0x04000000 )
00206 {
00207 # if defined(CAN_COMPILE_SSE)
00208
00209 psz_capability = "SSE2";
00210 i_illegal = 0;
00211
00212 if( setjmp( env ) == 0 )
00213 {
00214
00215 __asm__ __volatile__ ( "movupd %%xmm0, %%xmm0\n" : : );
00216 }
00217
00218 if( i_illegal == 0 )
00219 {
00220 i_capabilities |= CPU_CAPABILITY_SSE2;
00221 }
00222 # endif
00223 }
00224
00225
00226 cpuid( 0x80000000 );
00227
00228 if( i_eax < 0x80000001 )
00229 {
00230 # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) \
00231 && defined( HAVE_SIGNAL_H )
00232 signal( SIGILL, pf_sigill );
00233 # endif
00234 return i_capabilities;
00235 }
00236
00237
00238 cpuid( 0x80000001 );
00239
00240 # ifdef CAN_COMPILE_3DNOW
00241 if( i_edx & 0x80000000 )
00242 {
00243 psz_capability = "3D Now!";
00244 i_illegal = 0;
00245
00246 if( setjmp( env ) == 0 )
00247 {
00248
00249 __asm__ __volatile__ ( "pfadd %%mm0,%%mm0\n" "femms\n" : : );
00250 }
00251
00252 if( i_illegal == 0 )
00253 {
00254 i_capabilities |= CPU_CAPABILITY_3DNOW;
00255 }
00256 }
00257 # endif
00258
00259 if( b_amd && ( i_edx & 0x00400000 ) )
00260 {
00261 i_capabilities |= CPU_CAPABILITY_MMXEXT;
00262 }
00263
00264 # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) \
00265 && defined( HAVE_SIGNAL_H )
00266 signal( SIGILL, pf_sigill );
00267 # endif
00268 return i_capabilities;
00269
00270 #elif defined( __powerpc__ )
00271
00272 # ifdef CAN_COMPILE_ALTIVEC && defined( HAVE_SIGNAL_H )
00273 void (*pf_sigill) (int) = signal( SIGILL, SigHandler );
00274
00275 i_capabilities |= CPU_CAPABILITY_FPU;
00276
00277 i_illegal = 0;
00278
00279 if( setjmp( env ) == 0 )
00280 {
00281 asm volatile ("mtspr 256, %0\n\t"
00282 "vand %%v0, %%v0, %%v0"
00283 :
00284 : "r" (-1));
00285 }
00286
00287 if( i_illegal == 0 )
00288 {
00289 i_capabilities |= CPU_CAPABILITY_ALTIVEC;
00290 }
00291
00292 signal( SIGILL, pf_sigill );
00293 # endif
00294
00295 return i_capabilities;
00296
00297 #elif defined( __sparc__ )
00298
00299 i_capabilities |= CPU_CAPABILITY_FPU;
00300 return i_capabilities;
00301
00302 #elif defined( _MSC_VER ) && !defined( UNDER_CE )
00303 i_capabilities |= CPU_CAPABILITY_FPU;
00304 return i_capabilities;
00305
00306 #else
00307
00308 return i_capabilities;
00309
00310 #endif
00311 }
00312
00313
00314
00315
00316
00317
00318
00319 #if defined( HAVE_SIGNAL_H )
00320 static void SigHandler( int i_signal )
00321 {
00322
00323 i_illegal = 1;
00324
00325 #ifdef HAVE_SIGRELSE
00326 sigrelse( i_signal );
00327 #endif
00328
00329 #if defined( __i386__ )
00330 fprintf( stderr, "warning: your CPU has %s instructions, but not your "
00331 "operating system.\n", psz_capability );
00332 fprintf( stderr, " some optimizations will be disabled unless "
00333 "you upgrade your OS\n" );
00334 # if defined( SYS_LINUX )
00335 fprintf( stderr, " (for instance Linux kernel 2.4.x or later)\n" );
00336 # endif
00337 #endif
00338
00339 longjmp( env, 1 );
00340 }
00341 #endif
00342