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 #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
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)
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_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 std::swap(cpuid[2], cpuid[3]);
00165 if (memcmp(cpuid+1, "GenuineIntel", 12) == 0)
00166 {
00167 g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf;
00168 g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1);
00169 }
00170 else if (memcmp(cpuid+1, "AuthenticAMD", 12) == 0)
00171 {
00172 CpuId(0x80000005, cpuid);
00173 g_cacheLineSize = GETBYTE(cpuid[2], 0);
00174 }
00175
00176 if (!g_cacheLineSize)
00177 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
00178
00179 g_x86DetectionDone = true;
00180 }
00181
00182 #endif
00183
00184 NAMESPACE_END
00185
00186 #endif