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
00030
00031
00032
00033 #include "u_cpu_detect.h"
00034
00035 #ifdef __linux__
00036 #define OS_LINUX
00037 #endif
00038 #ifdef WIN32
00039 #define OS_WIN32
00040 #endif
00041
00042 #if defined(ARCH_POWERPC)
00043 #if defined(OS_DARWIN)
00044 #include <sys/sysctl.h>
00045 #else
00046 #include <signal.h>
00047 #include <setjmp.h>
00048 #endif
00049 #endif
00050
00051 #if defined(OS_NETBSD) || defined(OS_OPENBSD)
00052 #include <sys/param.h>
00053 #include <sys/sysctl.h>
00054 #include <machine/cpu.h>
00055 #endif
00056
00057 #if defined(OS_FREEBSD)
00058 #include <sys/types.h>
00059 #include <sys/sysctl.h>
00060 #endif
00061
00062 #if defined(OS_LINUX)
00063 #include <signal.h>
00064 #endif
00065
00066 #if defined(OS_WIN32)
00067 #include <windows.h>
00068 #endif
00069
00070 #include <stdio.h>
00071 #include <stdlib.h>
00072 #include <unistd.h>
00073 #include <string.h>
00074
00075
00076 static struct cpu_detect_caps __cpu_detect_caps;
00077 static int __cpu_detect_initialized = 0;
00078
00079 static int has_cpuid(void);
00080 static int cpuid(unsigned int ax, unsigned int *p);
00081
00082
00083 #if defined(ARCH_X86)
00084 #if defined(OS_LINUX) && defined(_POSIX_SOURCE) && defined(X86_FXSR_MAGIC)
00085 static void sigill_handler_sse(int signal, struct sigcontext sc)
00086 {
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 sc.eip += 3;
00098
00099 __cpu_detect_caps.hasSSE=0;
00100 }
00101
00102 static void sigfpe_handler_sse(int signal, struct sigcontext sc)
00103 {
00104 if (sc.fpstate->magic != 0xffff) {
00105
00106
00107
00108
00109 sc.fpstate->mxcsr |= 0x00000200;
00110 sc.fpstate->mxcsr &= 0xfffffffb;
00111 } else {
00112
00113
00114 }
00115 }
00116 #endif
00117 #endif
00118
00119 #if defined(OS_WIN32)
00120 LONG CALLBACK win32_sig_handler_sse(EXCEPTION_POINTERS* ep)
00121 {
00122 if(ep->ExceptionRecord->ExceptionCode==EXCEPTION_ILLEGAL_INSTRUCTION){
00123 ep->ContextRecord->Eip +=3;
00124 __cpu_detect_caps.hasSSE=0;
00125 return EXCEPTION_CONTINUE_EXECUTION;
00126 }
00127 return EXCEPTION_CONTINUE_SEARCH;
00128 }
00129 #endif
00130
00131
00132 #if defined(ARCH_POWERPC) && !defined(OS_DARWIN)
00133 static sigjmp_buf __lv_powerpc_jmpbuf;
00134 static volatile sig_atomic_t __lv_powerpc_canjump = 0;
00135
00136 static void sigill_handler (int sig);
00137
00138 static void sigill_handler (int sig)
00139 {
00140 if (!__lv_powerpc_canjump) {
00141 signal (sig, SIG_DFL);
00142 raise (sig);
00143 }
00144
00145 __lv_powerpc_canjump = 0;
00146 siglongjmp(__lv_powerpc_jmpbuf, 1);
00147 }
00148
00149 static void check_os_altivec_support(void)
00150 {
00151 #if defined(OS_DARWIN)
00152 int sels[2] = {CTL_HW, HW_VECTORUNIT};
00153 int has_vu = 0;
00154 int len = sizeof (has_vu);
00155 int err;
00156
00157 err = sysctl(sels, 2, &has_vu, &len, NULL, 0);
00158
00159 if (err == 0) {
00160 if (has_vu != 0) {
00161 __cpu_detect_caps.hasAltiVec = 1;
00162 }
00163 }
00164 #else
00165
00166
00167 signal(SIGILL, sigill_handler);
00168 if (sigsetjmp(__lv_powerpc_jmpbuf, 1)) {
00169 signal(SIGILL, SIG_DFL);
00170 } else {
00171 __lv_powerpc_canjump = 1;
00172
00173 __asm __volatile
00174 ("mtspr 256, %0\n\t"
00175 "vand %%v0, %%v0, %%v0"
00176 :
00177 : "r" (-1));
00178
00179 signal(SIGILL, SIG_DFL);
00180 __cpu_detect_caps.hasAltiVec = 1;
00181 }
00182 #endif
00183 }
00184 #endif
00185
00186
00187
00188
00189
00190
00191
00192 static void check_os_katmai_support(void)
00193 {
00194 #if defined(ARCH_X86)
00195 #if defined(OS_FREEBSD)
00196 int has_sse=0, ret;
00197 int len = sizeof (has_sse);
00198
00199 ret = sysctlbyname("hw.instruction_sse", &has_sse, &len, NULL, 0);
00200 if (ret || !has_sse)
00201 __cpu_detect_caps.hasSSE=0;
00202
00203 #elif defined(OS_NETBSD) || defined(OS_OPENBSD)
00204 int has_sse, has_sse2, ret, mib[2];
00205 int varlen;
00206
00207 mib[0] = CTL_MACHDEP;
00208 mib[1] = CPU_SSE;
00209 varlen = sizeof (has_sse);
00210
00211 ret = sysctl(mib, 2, &has_sse, &varlen, NULL, 0);
00212 if (ret < 0 || !has_sse) {
00213 __cpu_detect_caps.hasSSE = 0;
00214 } else {
00215 __cpu_detect_caps.hasSSE = 1;
00216 }
00217
00218 mib[1] = CPU_SSE2;
00219 varlen = sizeof (has_sse2);
00220 ret = sysctl(mib, 2, &has_sse2, &varlen, NULL, 0);
00221 if (ret < 0 || !has_sse2) {
00222 __cpu_detect_caps.hasSSE2 = 0;
00223 } else {
00224 __cpu_detect_caps.hasSSE2 = 1;
00225 }
00226 __cpu_detect_caps.hasSSE = 0;
00227
00228 #elif defined(OS_WIN32)
00229 LPTOP_LEVEL_EXCEPTION_FILTER exc_fil;
00230 if (__cpu_detect_caps.hasSSE) {
00231 exc_fil = SetUnhandledExceptionFilter(win32_sig_handler_sse);
00232 __asm __volatile ("xorps %xmm0, %xmm0");
00233 SetUnhandledExceptionFilter(exc_fil);
00234 }
00235 #elif defined(OS_LINUX)
00236 struct sigaction saved_sigill;
00237 struct sigaction saved_sigfpe;
00238
00239
00240
00241 sigaction(SIGILL, NULL, &saved_sigill);
00242 sigaction(SIGFPE, NULL, &saved_sigfpe);
00243
00244 signal(SIGILL, (void (*)(int))sigill_handler_sse);
00245 signal(SIGFPE, (void (*)(int))sigfpe_handler_sse);
00246
00247
00248
00249
00250
00251
00252
00253 if (__cpu_detect_caps.hasSSE) {
00254 __asm __volatile ("xorps %xmm1, %xmm0");
00255 }
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 if (__cpu_detect_caps.hasSSE) {
00271
00272 }
00273
00274
00275
00276 sigaction(SIGILL, &saved_sigill, NULL);
00277 sigaction(SIGFPE, &saved_sigfpe, NULL);
00278
00279 #else
00280
00281
00282
00283 __cpu_detect_caps.hasSSE = 0;
00284 #endif
00285 #endif
00286 }
00287
00288
00289 static int has_cpuid(void)
00290 {
00291 #if defined(ARCH_X86)
00292 int a, c;
00293
00294 __asm __volatile
00295 ("pushf\n"
00296 "popl %0\n"
00297 "movl %0, %1\n"
00298 "xorl $0x200000, %0\n"
00299 "push %0\n"
00300 "popf\n"
00301 "pushf\n"
00302 "popl %0\n"
00303 : "=a" (a), "=c" (c)
00304 :
00305 : "cc");
00306
00307 return a != c;
00308 #else
00309 return 0;
00310 #endif
00311 }
00312
00313 static int cpuid(unsigned int ax, unsigned int *p)
00314 {
00315 #if defined(ARCH_X86)
00316 unsigned int flags;
00317
00318 __asm __volatile
00319 ("movl %%ebx, %%esi\n\t"
00320 "cpuid\n\t"
00321 "xchgl %%ebx, %%esi"
00322 : "=a" (p[0]), "=S" (p[1]),
00323 "=c" (p[2]), "=d" (p[3])
00324 : "0" (ax));
00325
00326 return 0;
00327 #else
00328 return -1;
00329 #endif
00330 }
00331
00332 void cpu_detect_initialize()
00333 {
00334 unsigned int regs[4];
00335 unsigned int regs2[4];
00336
00337 int mib[2], ncpu;
00338 int len;
00339
00340 memset(&__cpu_detect_caps, 0, sizeof (struct cpu_detect_caps));
00341
00342
00343 #if defined(ARCH_MIPS)
00344 __cpu_detect_caps.type = CPU_DETECT_TYPE_MIPS;
00345 #elif defined(ARCH_ALPHA)
00346 __cpu_detect_caps.type = CPU_DETECT_TYPE_ALPHA;
00347 #elif defined(ARCH_SPARC)
00348 __cpu_detect_caps.type = CPU_DETECT_TYPE_SPARC;
00349 #elif defined(ARCH_X86)
00350 __cpu_detect_caps.type = CPU_DETECT_TYPE_X86;
00351 #elif defined(ARCH_POWERPC)
00352 __cpu_detect_caps.type = CPU_DETECT_TYPE_POWERPC;
00353 #else
00354 __cpu_detect_caps.type = CPU_DETECT_TYPE_OTHER;
00355 #endif
00356
00357
00358 #if !defined(OS_WIN32) && !defined(OS_UNKNOWN) && defined(_SC_NPROCESSORS_ONLN)
00359 __cpu_detect_caps.nrcpu = sysconf(_SC_NPROCESSORS_ONLN);
00360 if (__cpu_detect_caps.nrcpu == -1)
00361 __cpu_detect_caps.nrcpu = 1;
00362
00363 #elif defined(OS_NETBSD) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
00364
00365 mib[0] = CTL_HW;
00366 mib[1] = HW_NCPU;
00367
00368 len = sizeof (ncpu);
00369 sysctl(mib, 2, &ncpu, &len, NULL, 0);
00370 __cpu_detect_caps.nrcpu = ncpu;
00371
00372 #else
00373 __cpu_detect_caps.nrcpu = 1;
00374 #endif
00375
00376 #if defined(ARCH_X86)
00377
00378 if (has_cpuid() == 0)
00379 return;
00380
00381 __cpu_detect_caps.cacheline = 32;
00382
00383
00384 cpuid(0x00000000, regs);
00385
00386 if (regs[0] >= 0x00000001) {
00387 unsigned int cacheline;
00388
00389 cpuid (0x00000001, regs2);
00390
00391 __cpu_detect_caps.x86cpuType = (regs2[0] >> 8) & 0xf;
00392 if (__cpu_detect_caps.x86cpuType == 0xf)
00393 __cpu_detect_caps.x86cpuType = 8 + ((regs2[0] >> 20) & 255);
00394
00395
00396 __cpu_detect_caps.hasTSC = (regs2[3] & (1 << 8 )) >> 8;
00397 __cpu_detect_caps.hasMMX = (regs2[3] & (1 << 23 )) >> 23;
00398 __cpu_detect_caps.hasSSE = (regs2[3] & (1 << 25 )) >> 25;
00399 __cpu_detect_caps.hasSSE2 = (regs2[3] & (1 << 26 )) >> 26;
00400 __cpu_detect_caps.hasSSE3 = (regs2[2] & (1));
00401 __cpu_detect_caps.hasSSSE3 = (regs2[2] & (1 << 9 )) >> 9;
00402 __cpu_detect_caps.hasMMX2 = __cpu_detect_caps.hasSSE;
00403
00404 cacheline = ((regs2[1] >> 8) & 0xFF) * 8;
00405 if (cacheline > 0)
00406 __cpu_detect_caps.cacheline = cacheline;
00407 }
00408
00409 cpuid(0x80000000, regs);
00410
00411 if (regs[0] >= 0x80000001) {
00412
00413 cpuid(0x80000001, regs2);
00414
00415 __cpu_detect_caps.hasMMX |= (regs2[3] & (1 << 23 )) >> 23;
00416 __cpu_detect_caps.hasMMX2 |= (regs2[3] & (1 << 22 )) >> 22;
00417 __cpu_detect_caps.has3DNow = (regs2[3] & (1 << 31 )) >> 31;
00418 __cpu_detect_caps.has3DNowExt = (regs2[3] & (1 << 30 )) >> 30;
00419 }
00420
00421 if (regs[0] >= 0x80000006) {
00422 cpuid(0x80000006, regs2);
00423 __cpu_detect_caps.cacheline = regs2[2] & 0xFF;
00424 }
00425
00426
00427 #if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_NETBSD) || defined(OS_CYGWIN) || defined(OS_OPENBSD)
00428 if (__cpu_detect_caps.hasSSE)
00429 check_os_katmai_support();
00430
00431 if (!__cpu_detect_caps.hasSSE) {
00432 __cpu_detect_caps.hasSSE2 = 0;
00433 __cpu_detect_caps.hasSSE3 = 0;
00434 __cpu_detect_caps.hasSSSE3 = 0;
00435 }
00436 #else
00437 __cpu_detect_caps.hasSSE = 0;
00438 __cpu_detect_caps.hasSSE2 = 0;
00439 __cpu_detect_caps.hasSSE3 = 0;
00440 __cpu_detect_caps.hasSSSE3 = 0;
00441 #endif
00442 #endif
00443
00444 #if defined(ARCH_POWERPC)
00445 check_os_altivec_support();
00446 #endif
00447
00448 __cpu_detect_initialized = 1;
00449 }
00450
00451 struct cpu_detect_caps *cpu_detect_get_caps()
00452 {
00453 return &__cpu_detect_caps;
00454 }
00455
00456
00457 int cpu_detect_get_tsc()
00458 {
00459 return __cpu_detect_caps.hasTSC;
00460 }
00461
00462 int cpu_detect_get_mmx()
00463 {
00464 return __cpu_detect_caps.hasMMX;
00465 }
00466
00467 int cpu_detect_get_mmx2()
00468 {
00469 return __cpu_detect_caps.hasMMX2;
00470 }
00471
00472 int cpu_detect_get_sse()
00473 {
00474 return __cpu_detect_caps.hasSSE;
00475 }
00476
00477 int cpu_detect_get_sse2()
00478 {
00479 return __cpu_detect_caps.hasSSE2;
00480 }
00481
00482 int cpu_detect_get_sse3()
00483 {
00484 return __cpu_detect_caps.hasSSE3;
00485 }
00486
00487 int cpu_detect_get_ssse3()
00488 {
00489 return __cpu_detect_caps.hasSSSE3;
00490 }
00491
00492 int cpu_detect_get_3dnow()
00493 {
00494 return __cpu_detect_caps.has3DNow;
00495 }
00496
00497 int cpu_detect_get_3dnow2()
00498 {
00499 return __cpu_detect_caps.has3DNowExt;
00500 }
00501
00502 int cpu_detect_get_altivec()
00503 {
00504 return __cpu_detect_caps.hasAltiVec;
00505 }
00506