cpu.cpp

00001 // cpu.cpp - written and placed in the public domain by Wei Dai
00002 
00003 #include "pch.h"
00004 
00005 #ifndef CRYPTOPP_IMPORTS
00006 
00007 #include "cpu.h"
00008 #include "misc.h"
00009 #include <algorithm>
00010 
00011 #ifdef __GNUC__
00012 #include <signal.h>
00013 #include <setjmp.h>
00014 #endif
00015 
00016 #ifdef CRYPTOPP_MSVC6PP_OR_LATER
00017 #include <emmintrin.h>
00018 #endif
00019 
00020 NAMESPACE_BEGIN(CryptoPP)
00021 
00022 #ifdef CRYPTOPP_X86_ASM_AVAILABLE
00023 
00024 #ifndef _MSC_VER
00025 typedef void (*SigHandler)(int);
00026 
00027 static jmp_buf s_jmpNoCPUID;
00028 static void SigIllHandlerCPUID(int)
00029 {
00030         longjmp(s_jmpNoCPUID, 1);
00031 }
00032 #endif
00033 
00034 bool CpuId(word32 input, word32 *output)
00035 {
00036 #ifdef _MSC_VER
00037     __try
00038         {
00039                 __asm
00040                 {
00041                         mov eax, input
00042                         cpuid
00043                         mov edi, output
00044                         mov [edi], eax
00045                         mov [edi+4], ebx
00046                         mov [edi+8], ecx
00047                         mov [edi+12], edx
00048                 }
00049         }
00050     __except (1)
00051         {
00052                 return false;
00053     }
00054         return true;
00055 #else
00056         SigHandler oldHandler = signal(SIGILL, SigIllHandlerCPUID);
00057         if (oldHandler == SIG_ERR)
00058                 return false;
00059 
00060         bool result = true;
00061         if (setjmp(s_jmpNoCPUID))
00062                 result = false;
00063         else
00064         {
00065                 __asm__
00066                 (
00067                         // save ebx in case -fPIC is being used
00068 #if CRYPTOPP_BOOL_X86
00069                         "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
00070 #else
00071                         "pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx"
00072 #endif
00073                         : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3])
00074                         : "a" (input)
00075                 );
00076         }
00077 
00078         signal(SIGILL, oldHandler);
00079         return result;
00080 #endif
00081 }
00082 
00083 #ifndef _MSC_VER
00084 static jmp_buf s_jmpNoSSE2;
00085 static void SigIllHandlerSSE2(int)
00086 {
00087         longjmp(s_jmpNoSSE2, 1);
00088 }
00089 #endif
00090 
00091 #elif _MSC_VER >= 1400 && CRYPTOPP_BOOL_X64
00092 
00093 bool CpuId(word32 input, word32 *output)
00094 {
00095         __cpuid((int *)output, input);
00096         return true;
00097 }
00098 
00099 #endif
00100 
00101 #ifdef CRYPTOPP_CPUID_AVAILABLE
00102 
00103 static bool TrySSE2()
00104 {
00105 #if CRYPTOPP_BOOL_X64
00106         return true;
00107 #elif defined(_MSC_VER)
00108     __try
00109         {
00110 #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
00111         AS2(por xmm0, xmm0)        // executing SSE2 instruction
00112 #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
00113                 __mm128i x = _mm_setzero_si128();
00114                 return _mm_cvtsi128_si32(x) == 0;
00115 #endif
00116         }
00117     __except (1)
00118         {
00119                 return false;
00120     }
00121         return true;
00122 #elif defined(__GNUC__)
00123         SigHandler oldHandler = signal(SIGILL, SigIllHandlerSSE2);
00124         if (oldHandler == SIG_ERR)
00125                 return false;
00126 
00127         bool result = true;
00128         if (setjmp(s_jmpNoSSE2))
00129                 result = false;
00130         else
00131         {
00132 #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
00133                 __asm __volatile ("por %xmm0, %xmm0");
00134 #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
00135                 __mm128i x = _mm_setzero_si128();
00136                 result = _mm_cvtsi128_si32(x) == 0;
00137 #endif
00138         }
00139 
00140         signal(SIGILL, oldHandler);
00141         return result;
00142 #else
00143         return false;
00144 #endif
00145 }
00146 
00147 bool g_x86DetectionDone = false;
00148 bool g_hasSSE2 = false, g_hasSSSE3 = false, g_hasMMX = false, g_isP4 = false;
00149 word32 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
00150 
00151 void DetectX86Features()
00152 {
00153         word32 cpuid[4], cpuid1[4];
00154         if (!CpuId(0, cpuid))
00155                 return;
00156         if (!CpuId(1, cpuid1))
00157                 return;
00158 
00159         g_hasMMX = (cpuid1[3] & (1 << 23)) != 0;
00160         if ((cpuid1[3] & (1 << 26)) != 0)
00161                 g_hasSSE2 = TrySSE2();
00162         g_hasSSSE3 = g_hasSSE2 && (cpuid1[2] & (1<<9));
00163 
00164         std::swap(cpuid[2], cpuid[3]);
00165         if (memcmp(cpuid+1, "GenuineIntel", 12) == 0)
00166         {
00167                 g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf;
00168                 g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1);
00169         }
00170         else if (memcmp(cpuid+1, "AuthenticAMD", 12) == 0)
00171         {
00172                 CpuId(0x80000005, cpuid);
00173                 g_cacheLineSize = GETBYTE(cpuid[2], 0);
00174         }
00175 
00176         if (!g_cacheLineSize)
00177                 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
00178 
00179         g_x86DetectionDone = true;
00180 }
00181 
00182 #endif
00183 
00184 NAMESPACE_END
00185 
00186 #endif

Generated on Fri Jun 1 11:11:20 2007 for Crypto++ by  doxygen 1.5.2