- Main Page
- Namespaces
- Classes
- Files

# 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_hasISSE = false, 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         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