00001
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
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)
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