Crypto++
|
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