• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

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 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
00012 #include <signal.h>
00013 #include <setjmp.h>
00014 #endif
00015 
00016 #if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
00017 #include <emmintrin.h>
00018 #endif
00019 
00020 NAMESPACE_BEGIN(CryptoPP)
00021 
00022 #ifdef CRYPTOPP_CPUID_AVAILABLE
00023 
00024 #if _MSC_VER >= 1400 && CRYPTOPP_BOOL_X64
00025 
00026 bool CpuId(word32 input, word32 *output)
00027 {
00028         __cpuid((int *)output, input);
00029         return true;
00030 }
00031 
00032 #else
00033 
00034 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
00035 extern "C" {
00036 typedef void (*SigHandler)(int);
00037 
00038 static jmp_buf s_jmpNoCPUID;
00039 static void SigIllHandlerCPUID(int)
00040 {
00041         longjmp(s_jmpNoCPUID, 1);
00042 }
00043 
00044 static jmp_buf s_jmpNoSSE2;
00045 static void SigIllHandlerSSE2(int)
00046 {
00047         longjmp(s_jmpNoSSE2, 1);
00048 }
00049 }
00050 #endif
00051 
00052 bool CpuId(word32 input, word32 *output)
00053 {
00054 #ifdef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
00055     __try
00056         {
00057                 __asm
00058                 {
00059                         mov eax, input
00060                         cpuid
00061                         mov edi, output
00062                         mov [edi], eax
00063                         mov [edi+4], ebx
00064                         mov [edi+8], ecx
00065                         mov [edi+12], edx
00066                 }
00067         }
00068     __except (1)
00069         {
00070                 return false;
00071     }
00072         return true;
00073 #else
00074         SigHandler oldHandler = signal(SIGILL, SigIllHandlerCPUID);
00075         if (oldHandler == SIG_ERR)
00076                 return false;
00077 
00078         bool result = true;
00079         if (setjmp(s_jmpNoCPUID))
00080                 result = false;
00081         else
00082         {
00083                 asm
00084                 (
00085                         // save ebx in case -fPIC is being used
00086 #if CRYPTOPP_BOOL_X86
00087                         "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
00088 #else
00089                         "pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx"
00090 #endif
00091                         : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3])
00092                         : "a" (input)
00093                 );
00094         }
00095 
00096         signal(SIGILL, oldHandler);
00097         return result;
00098 #endif
00099 }
00100 
00101 #endif
00102 
00103 static bool TrySSE2()
00104 {
00105 #if CRYPTOPP_BOOL_X64
00106         return true;
00107 #elif defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
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                 __m128i 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 #else
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                 __m128i x = _mm_setzero_si128();
00136                 result = _mm_cvtsi128_si32(x) == 0;
00137 #endif
00138         }
00139 
00140         signal(SIGILL, oldHandler);
00141         return result;
00142 #endif
00143 }
00144 
00145 bool g_x86DetectionDone = false;
00146 bool g_hasISSE = false, g_hasSSE2 = false, g_hasSSSE3 = false, g_hasMMX = false, g_hasAESNI = false, g_hasCLMUL = false, g_isP4 = false;
00147 word32 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
00148 
00149 void DetectX86Features()
00150 {
00151         word32 cpuid[4], cpuid1[4];
00152         if (!CpuId(0, cpuid))
00153                 return;
00154         if (!CpuId(1, cpuid1))
00155                 return;
00156 
00157         g_hasMMX = (cpuid1[3] & (1 << 23)) != 0;
00158         if ((cpuid1[3] & (1 << 26)) != 0)
00159                 g_hasSSE2 = TrySSE2();
00160         g_hasSSSE3 = g_hasSSE2 && (cpuid1[2] & (1<<9));
00161         g_hasAESNI = g_hasSSE2 && (cpuid1[2] & (1<<25));
00162         g_hasCLMUL = g_hasSSE2 && (cpuid1[2] & (1<<1));
00163 
00164         if ((cpuid1[3] & (1 << 25)) != 0)
00165                 g_hasISSE = true;
00166         else
00167         {
00168                 word32 cpuid2[4];
00169                 CpuId(0x080000000, cpuid2);
00170                 if (cpuid2[0] >= 0x080000001)
00171                 {
00172                         CpuId(0x080000001, cpuid2);
00173                         g_hasISSE = (cpuid2[3] & (1 << 22)) != 0;
00174                 }
00175         }
00176 
00177         std::swap(cpuid[2], cpuid[3]);
00178         if (memcmp(cpuid+1, "GenuineIntel", 12) == 0)
00179         {
00180                 g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf;
00181                 g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1);
00182         }
00183         else if (memcmp(cpuid+1, "AuthenticAMD", 12) == 0)
00184         {
00185                 CpuId(0x80000005, cpuid);
00186                 g_cacheLineSize = GETBYTE(cpuid[2], 0);
00187         }
00188 
00189         if (!g_cacheLineSize)
00190                 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
00191 
00192         g_x86DetectionDone = true;
00193 }
00194 
00195 #endif
00196 
00197 NAMESPACE_END
00198 
00199 #endif

Generated on Mon Aug 9 2010 15:56:33 for Crypto++ by  doxygen 1.7.1