Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

268 lines
6.1 KiB

  1. // cpu.cpp - written and placed in the public domain by Wei Dai
  2. #include "pch.h"
  3. #include "config.h"
  4. #ifndef EXCEPTION_EXECUTE_HANDLER
  5. # define EXCEPTION_EXECUTE_HANDLER 1
  6. #endif
  7. #ifndef CRYPTOPP_IMPORTS
  8. #include "cpu.h"
  9. #include "misc.h"
  10. #include <algorithm>
  11. #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
  12. #include <signal.h>
  13. #include <setjmp.h>
  14. #endif
  15. #if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
  16. #include <emmintrin.h>
  17. #endif
  18. NAMESPACE_BEGIN(CryptoPP)
  19. #ifdef CRYPTOPP_CPUID_AVAILABLE
  20. #if _MSC_VER >= 1400 && CRYPTOPP_BOOL_X64
  21. bool CpuId(word32 input, word32 output[4])
  22. {
  23. __cpuid((int *)output, input);
  24. return true;
  25. }
  26. #elif defined(__APPLE__) // VALVE edit for cpuid intrinsic on OSX
  27. #include <cpuid.h>
  28. bool CpuId(word32 input, word32 output[4])
  29. {
  30. __cpuid( input, output[0], output[1], output[2], output[3] );
  31. return true;
  32. }
  33. #else
  34. #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
  35. extern "C" {
  36. typedef void (*SigHandler)(int);
  37. static jmp_buf s_jmpNoCPUID;
  38. static void SigIllHandlerCPUID(int)
  39. {
  40. longjmp(s_jmpNoCPUID, 1);
  41. }
  42. static jmp_buf s_jmpNoSSE2;
  43. static void SigIllHandlerSSE2(int)
  44. {
  45. longjmp(s_jmpNoSSE2, 1);
  46. }
  47. }
  48. #endif
  49. bool CpuId(word32 input, word32 output[4])
  50. {
  51. #if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
  52. __try
  53. {
  54. __asm
  55. {
  56. mov eax, input
  57. mov ecx, 0
  58. cpuid
  59. mov edi, output
  60. mov [edi], eax
  61. mov [edi+4], ebx
  62. mov [edi+8], ecx
  63. mov [edi+12], edx
  64. }
  65. }
  66. // GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION
  67. __except (EXCEPTION_EXECUTE_HANDLER)
  68. {
  69. return false;
  70. }
  71. // function 0 returns the highest basic function understood in EAX
  72. if(input == 0)
  73. return !!output[0];
  74. return true;
  75. #else
  76. // longjmp and clobber warnings. Volatile is required.
  77. // http://github.com/weidai11/cryptopp/issues/24
  78. // http://stackoverflow.com/q/7721854
  79. volatile bool result = true;
  80. SigHandler oldHandler = signal(SIGILL, SigIllHandlerCPUID);
  81. if (oldHandler == SIG_ERR)
  82. result = false;
  83. if (setjmp(s_jmpNoCPUID))
  84. result = false;
  85. else
  86. {
  87. asm volatile
  88. (
  89. // save ebx in case -fPIC is being used
  90. // TODO: this might need an early clobber on EDI.
  91. # if CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
  92. "pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx"
  93. # else
  94. "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
  95. # endif
  96. : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3])
  97. : "a" (input), "c" (0)
  98. );
  99. }
  100. signal(SIGILL, oldHandler);
  101. return result;
  102. #endif
  103. }
  104. #endif
  105. static bool TrySSE2()
  106. {
  107. #if CRYPTOPP_BOOL_X64
  108. return true;
  109. #elif defined(__APPLE__) // VALVE edit - assume SSE2 on Mac targets
  110. return true;
  111. #elif defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
  112. __try
  113. {
  114. #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
  115. AS2(por xmm0, xmm0) // executing SSE2 instruction
  116. #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
  117. __m128i x = _mm_setzero_si128();
  118. return _mm_cvtsi128_si32(x) == 0;
  119. #endif
  120. }
  121. // GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION
  122. __except (EXCEPTION_EXECUTE_HANDLER)
  123. {
  124. return false;
  125. }
  126. return true;
  127. #else
  128. // longjmp and clobber warnings. Volatile is required.
  129. // http://github.com/weidai11/cryptopp/issues/24
  130. // http://stackoverflow.com/q/7721854
  131. volatile bool result = true;
  132. SigHandler oldHandler = signal(SIGILL, SigIllHandlerSSE2);
  133. if (oldHandler == SIG_ERR)
  134. return false;
  135. if (setjmp(s_jmpNoSSE2))
  136. result = true;
  137. else
  138. {
  139. #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
  140. __asm __volatile ("por %xmm0, %xmm0");
  141. #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
  142. __m128i x = _mm_setzero_si128();
  143. result = _mm_cvtsi128_si32(x) == 0;
  144. #endif
  145. }
  146. signal(SIGILL, oldHandler);
  147. return result;
  148. #endif
  149. }
  150. bool g_x86DetectionDone = false;
  151. 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;
  152. word32 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
  153. // MacPorts/GCC does not provide constructor(priority). Apple/GCC and Fink/GCC do provide it.
  154. #define HAVE_GCC_CONSTRUCTOR1 (__GNUC__ && (CRYPTOPP_INIT_PRIORITY > 0) && ((CRYPTOPP_GCC_VERSION >= 40300) || (CRYPTOPP_CLANG_VERSION >= 20900) || (_INTEL_COMPILER >= 300)) && !(MACPORTS_GCC_COMPILER > 0))
  155. #define HAVE_GCC_CONSTRUCTOR0 (__GNUC__ && (CRYPTOPP_INIT_PRIORITY > 0) && !(MACPORTS_GCC_COMPILER > 0))
  156. static inline bool IsIntel(const word32 output[4])
  157. {
  158. // This is the "GenuineIntel" string
  159. return (output[1] /*EBX*/ == 0x756e6547) &&
  160. (output[2] /*ECX*/ == 0x6c65746e) &&
  161. (output[3] /*EDX*/ == 0x49656e69);
  162. }
  163. static inline bool IsAMD(const word32 output[4])
  164. {
  165. // This is the "AuthenticAMD" string
  166. return (output[1] /*EBX*/ == 0x68747541) &&
  167. (output[2] /*ECX*/ == 0x69746E65) &&
  168. (output[3] /*EDX*/ == 0x444D4163);
  169. }
  170. #if HAVE_GCC_CONSTRUCTOR1
  171. void __attribute__ ((constructor (CRYPTOPP_INIT_PRIORITY + 50))) DetectX86Features()
  172. #elif HAVE_GCC_CONSTRUCTOR0
  173. void __attribute__ ((constructor)) DetectX86Features()
  174. #else
  175. void DetectX86Features()
  176. #endif
  177. {
  178. word32 cpuid[4], cpuid1[4];
  179. if (!CpuId(0, cpuid))
  180. return;
  181. if (!CpuId(1, cpuid1))
  182. return;
  183. g_hasMMX = (cpuid1[3] & (1 << 23)) != 0;
  184. if ((cpuid1[3] & (1 << 26)) != 0)
  185. g_hasSSE2 = TrySSE2();
  186. g_hasSSSE3 = g_hasSSE2 && (cpuid1[2] & (1<<9));
  187. g_hasAESNI = g_hasSSE2 && (cpuid1[2] & (1<<25));
  188. g_hasCLMUL = g_hasSSE2 && (cpuid1[2] & (1<<1));
  189. if ((cpuid1[3] & (1 << 25)) != 0)
  190. g_hasISSE = true;
  191. else
  192. {
  193. word32 cpuid2[4];
  194. CpuId(0x080000000, cpuid2);
  195. if (cpuid2[0] >= 0x080000001)
  196. {
  197. CpuId(0x080000001, cpuid2);
  198. g_hasISSE = (cpuid2[3] & (1 << 22)) != 0;
  199. }
  200. }
  201. static const unsigned int RDRAND_FLAG = (1 << 30);
  202. static const unsigned int RDSEED_FLAG = (1 << 18);
  203. if (IsIntel(cpuid))
  204. {
  205. g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf;
  206. g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1);
  207. g_hasRDRAND = !!(cpuid1[2] /*ECX*/ & RDRAND_FLAG);
  208. if (cpuid[0] /*EAX*/ >= 7)
  209. {
  210. word32 cpuid3[4];
  211. if (CpuId(7, cpuid3))
  212. g_hasRDSEED = !!(cpuid3[1] /*EBX*/ & RDSEED_FLAG);
  213. }
  214. }
  215. else if (IsAMD(cpuid))
  216. {
  217. CpuId(0x80000005, cpuid);
  218. g_cacheLineSize = GETBYTE(cpuid[2], 0);
  219. g_hasRDRAND = !!(cpuid[2] /*ECX*/ & RDRAND_FLAG);
  220. }
  221. if (!g_cacheLineSize)
  222. g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
  223. *((volatile bool*)&g_x86DetectionDone) = true;
  224. }
  225. #endif
  226. NAMESPACE_END
  227. #endif