00001
00002
00003 #include "pch.h"
00004 #include "config.h"
00005
00006 #ifndef EXCEPTION_EXECUTE_HANDLER
00007 # define EXCEPTION_EXECUTE_HANDLER 1
00008 #endif
00009
00010 #ifndef CRYPTOPP_IMPORTS
00011
00012 #include "cpu.h"
00013 #include "misc.h"
00014 #include <algorithm>
00015
00016 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
00017 #include <signal.h>
00018 #include <setjmp.h>
00019 #endif
00020
00021 #if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
00022 #include <emmintrin.h>
00023 #endif
00024
00025 NAMESPACE_BEGIN(CryptoPP)
00026
00027 #ifdef CRYPTOPP_CPUID_AVAILABLE
00028
00029 #if _MSC_VER >= 1400 && CRYPTOPP_BOOL_X64
00030
00031 bool CpuId(word32 input, word32 output[4])
00032 {
00033 __cpuid((int *)output, input);
00034 return true;
00035 }
00036
00037 #else
00038
00039 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
00040 extern "C" {
00041 typedef void (*SigHandler)(int);
00042
00043 static jmp_buf s_jmpNoCPUID;
00044 static void SigIllHandlerCPUID(int)
00045 {
00046 longjmp(s_jmpNoCPUID, 1);
00047 }
00048
00049 static jmp_buf s_jmpNoSSE2;
00050 static void SigIllHandlerSSE2(int)
00051 {
00052 longjmp(s_jmpNoSSE2, 1);
00053 }
00054 }
00055 #endif
00056
00057 bool CpuId(word32 input, word32 output[4])
00058 {
00059 #if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
00060 __try
00061 {
00062 __asm
00063 {
00064 mov eax, input
00065 mov ecx, 0
00066 cpuid
00067 mov edi, output
00068 mov [edi], eax
00069 mov [edi+4], ebx
00070 mov [edi+8], ecx
00071 mov [edi+12], edx
00072 }
00073 }
00074
00075 __except (EXCEPTION_EXECUTE_HANDLER)
00076 {
00077 return false;
00078 }
00079
00080
00081 if(input == 0)
00082 return !!output[0];
00083
00084 return true;
00085 #else
00086
00087
00088
00089 volatile bool result = true;
00090
00091 SigHandler oldHandler = signal(SIGILL, SigIllHandlerCPUID);
00092 if (oldHandler == SIG_ERR)
00093 result = false;
00094
00095 if (setjmp(s_jmpNoCPUID))
00096 result = false;
00097 else
00098 {
00099 asm volatile
00100 (
00101
00102
00103 # if CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
00104 "pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx"
00105 # else
00106 "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
00107 # endif
00108 : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3])
00109 : "a" (input), "c" (0)
00110 );
00111 }
00112
00113 signal(SIGILL, oldHandler);
00114 return result;
00115 #endif
00116 }
00117
00118 #endif
00119
00120 static bool TrySSE2()
00121 {
00122 #if CRYPTOPP_BOOL_X64
00123 return true;
00124 #elif defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
00125 __try
00126 {
00127 #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
00128 AS2(por xmm0, xmm0)
00129 #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
00130 __m128i x = _mm_setzero_si128();
00131 return _mm_cvtsi128_si32(x) == 0;
00132 #endif
00133 }
00134
00135 __except (EXCEPTION_EXECUTE_HANDLER)
00136 {
00137 return false;
00138 }
00139 return true;
00140 #else
00141
00142
00143
00144 volatile bool result = true;
00145
00146 SigHandler oldHandler = signal(SIGILL, SigIllHandlerSSE2);
00147 if (oldHandler == SIG_ERR)
00148 return false;
00149
00150 if (setjmp(s_jmpNoSSE2))
00151 result = true;
00152 else
00153 {
00154 #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
00155 __asm __volatile ("por %xmm0, %xmm0");
00156 #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
00157 __m128i x = _mm_setzero_si128();
00158 result = _mm_cvtsi128_si32(x) == 0;
00159 #endif
00160 }
00161
00162 signal(SIGILL, oldHandler);
00163 return result;
00164 #endif
00165 }
00166
00167 bool g_x86DetectionDone = false;
00168 bool g_hasMMX = false, g_hasISSE = false, g_hasSSE2 = false, g_hasSSSE3 = false, g_hasAESNI = false, g_hasCLMUL = false, g_isP4 = false, g_hasRDRAND = false, g_hasRDSEED = false;
00169 word32 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
00170
00171
00172 #define HAVE_GCC_CONSTRUCTOR1 (__GNUC__ && (CRYPTOPP_INIT_PRIORITY > 0) && ((CRYPTOPP_GCC_VERSION >= 40300) || (CRYPTOPP_CLANG_VERSION >= 20900) || (_INTEL_COMPILER >= 300)) && !(MACPORTS_GCC_COMPILER > 0))
00173 #define HAVE_GCC_CONSTRUCTOR0 (__GNUC__ && (CRYPTOPP_INIT_PRIORITY > 0) && !(MACPORTS_GCC_COMPILER > 0))
00174
00175 static inline bool IsIntel(const word32 output[4])
00176 {
00177
00178 return (output[1] == 0x756e6547) &&
00179 (output[2] == 0x6c65746e) &&
00180 (output[3] == 0x49656e69);
00181 }
00182
00183 static inline bool IsAMD(const word32 output[4])
00184 {
00185
00186 return (output[1] == 0x68747541) &&
00187 (output[2] == 0x69746E65) &&
00188 (output[3] == 0x444D4163);
00189 }
00190
00191 #if HAVE_GCC_CONSTRUCTOR1
00192 void __attribute__ ((constructor (CRYPTOPP_INIT_PRIORITY + 50))) DetectX86Features()
00193 #elif HAVE_GCC_CONSTRUCTOR0
00194 void __attribute__ ((constructor)) DetectX86Features()
00195 #else
00196 void DetectX86Features()
00197 #endif
00198 {
00199 word32 cpuid[4], cpuid1[4];
00200 if (!CpuId(0, cpuid))
00201 return;
00202 if (!CpuId(1, cpuid1))
00203 return;
00204
00205 g_hasMMX = (cpuid1[3] & (1 << 23)) != 0;
00206 if ((cpuid1[3] & (1 << 26)) != 0)
00207 g_hasSSE2 = TrySSE2();
00208 g_hasSSSE3 = g_hasSSE2 && (cpuid1[2] & (1<<9));
00209 g_hasAESNI = g_hasSSE2 && (cpuid1[2] & (1<<25));
00210 g_hasCLMUL = g_hasSSE2 && (cpuid1[2] & (1<<1));
00211
00212 if ((cpuid1[3] & (1 << 25)) != 0)
00213 g_hasISSE = true;
00214 else
00215 {
00216 word32 cpuid2[4];
00217 CpuId(0x080000000, cpuid2);
00218 if (cpuid2[0] >= 0x080000001)
00219 {
00220 CpuId(0x080000001, cpuid2);
00221 g_hasISSE = (cpuid2[3] & (1 << 22)) != 0;
00222 }
00223 }
00224
00225 static const unsigned int RDRAND_FLAG = (1 << 30);
00226 static const unsigned int RDSEED_FLAG = (1 << 18);
00227 if (IsIntel(cpuid))
00228 {
00229 g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf;
00230 g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1);
00231 g_hasRDRAND = !!(cpuid1[2] & RDRAND_FLAG);
00232
00233 if (cpuid[0] >= 7)
00234 {
00235 word32 cpuid3[4];
00236 if (CpuId(7, cpuid3))
00237 g_hasRDSEED = !!(cpuid3[1] & RDSEED_FLAG);
00238 }
00239 }
00240 else if (IsAMD(cpuid))
00241 {
00242 CpuId(0x80000005, cpuid);
00243 g_cacheLineSize = GETBYTE(cpuid[2], 0);
00244 g_hasRDRAND = !!(cpuid[2] & RDRAND_FLAG);
00245 }
00246
00247 if (!g_cacheLineSize)
00248 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
00249
00250 *((volatile bool*)&g_x86DetectionDone) = true;
00251 }
00252
00253 #endif
00254
00255 NAMESPACE_END
00256
00257 #endif