runtime.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. #include <stddef.h>
  2. #include <stdint.h>
  3. #ifdef HAVE_ANDROID_GETCPUFEATURES
  4. # include <cpu-features.h>
  5. #endif
  6. #ifdef __APPLE__
  7. # include <sys/types.h>
  8. # include <sys/sysctl.h>
  9. # include <mach/machine.h>
  10. #endif
  11. #ifdef HAVE_SYS_AUXV_H
  12. # include <sys/auxv.h>
  13. #endif
  14. #include "private/common.h"
  15. #include "runtime.h"
  16. typedef struct CPUFeatures_ {
  17. int initialized;
  18. int has_neon;
  19. int has_armcrypto;
  20. int has_sse2;
  21. int has_sse3;
  22. int has_ssse3;
  23. int has_sse41;
  24. int has_avx;
  25. int has_avx2;
  26. int has_avx512f;
  27. int has_pclmul;
  28. int has_aesni;
  29. int has_rdrand;
  30. } CPUFeatures;
  31. static CPUFeatures _cpu_features;
  32. #define CPUID_EBX_AVX2 0x00000020
  33. #define CPUID_EBX_AVX512F 0x00010000
  34. #define CPUID_ECX_SSE3 0x00000001
  35. #define CPUID_ECX_PCLMUL 0x00000002
  36. #define CPUID_ECX_SSSE3 0x00000200
  37. #define CPUID_ECX_SSE41 0x00080000
  38. #define CPUID_ECX_AESNI 0x02000000
  39. #define CPUID_ECX_XSAVE 0x04000000
  40. #define CPUID_ECX_OSXSAVE 0x08000000
  41. #define CPUID_ECX_AVX 0x10000000
  42. #define CPUID_ECX_RDRAND 0x40000000
  43. #define CPUID_EDX_SSE2 0x04000000
  44. #define XCR0_SSE 0x00000002
  45. #define XCR0_AVX 0x00000004
  46. #define XCR0_OPMASK 0x00000020
  47. #define XCR0_ZMM_HI256 0x00000040
  48. #define XCR0_HI16_ZMM 0x00000080
  49. static int
  50. _sodium_runtime_arm_cpu_features(CPUFeatures * const cpu_features)
  51. {
  52. cpu_features->has_neon = 0;
  53. cpu_features->has_armcrypto = 0;
  54. #ifndef __ARM_ARCH
  55. return -1; /* LCOV_EXCL_LINE */
  56. #endif
  57. #if defined(__ARM_NEON) || defined(__aarch64__)
  58. cpu_features->has_neon = 1;
  59. #elif defined(HAVE_ANDROID_GETCPUFEATURES) && defined(ANDROID_CPU_ARM_FEATURE_NEON)
  60. cpu_features->has_neon =
  61. (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0x0;
  62. #elif defined(__aarch64__) && defined(AT_HWCAP)
  63. # ifdef HAVE_GETAUXVAL
  64. cpu_features->has_neon = (getauxval(AT_HWCAP) & (1L << 1)) != 0;
  65. # elif defined(HAVE_ELF_AUX_INFO)
  66. {
  67. unsigned long buf;
  68. if (elf_aux_info(AT_HWCAP, (void *) &buf, (int) sizeof buf) == 0) {
  69. cpu_features->has_neon = (buf & (1L << 1)) != 0;
  70. }
  71. }
  72. # endif
  73. #elif defined(__arm__) && defined(AT_HWCAP)
  74. # ifdef HAVE_GETAUXVAL
  75. cpu_features->has_neon = (getauxval(AT_HWCAP) & (1L << 12)) != 0;
  76. # elif defined(HAVE_ELF_AUX_INFO)
  77. {
  78. unsigned long buf;
  79. if (elf_aux_info(AT_HWCAP, (void *) &buf, (int) sizeof buf) == 0) {
  80. cpu_features->has_neon = (buf & (1L << 12)) != 0;
  81. }
  82. }
  83. # endif
  84. #endif
  85. if (cpu_features->has_neon == 0) {
  86. return 0;
  87. }
  88. #if __ARM_FEATURE_CRYPTO
  89. cpu_features->has_armcrypto = 1;
  90. #elif defined(__APPLE__) && defined(CPU_TYPE_ARM64) && defined(CPU_SUBTYPE_ARM64E)
  91. {
  92. cpu_type_t cpu_type;
  93. cpu_subtype_t cpu_subtype;
  94. size_t cpu_type_len = sizeof cpu_type;
  95. size_t cpu_subtype_len = sizeof cpu_subtype;
  96. if (sysctlbyname("hw.cputype", &cpu_type, &cpu_type_len,
  97. NULL, 0) == 0 && cpu_type == CPU_TYPE_ARM64 &&
  98. sysctlbyname("hw.cpusubtype", &cpu_subtype, &cpu_subtype_len,
  99. NULL, 0) == 0 &&
  100. (cpu_subtype == CPU_SUBTYPE_ARM64E ||
  101. cpu_subtype == CPU_SUBTYPE_ARM64_V8)) {
  102. cpu_features->has_armcrypto = 1;
  103. }
  104. }
  105. #elif defined(HAVE_ANDROID_GETCPUFEATURES) && defined(ANDROID_CPU_ARM_FEATURE_AES)
  106. cpu_features->has_armcrypto =
  107. (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_AES) != 0x0;
  108. #elif defined(__aarch64__) && defined(AT_HWCAP)
  109. # ifdef HAVE_GETAUXVAL
  110. cpu_features->has_armcrypto = (getauxval(AT_HWCAP) & (1L << 3)) != 0;
  111. # elif defined(HAVE_ELF_AUX_INFO)
  112. {
  113. unsigned long buf;
  114. if (elf_aux_info(AT_HWCAP, (void *) &buf, (int) sizeof buf) == 0) {
  115. cpu_features->has_armcrypto = (buf & (1L << 3)) != 0;
  116. }
  117. }
  118. # endif
  119. #elif defined(__arm__) && defined(AT_HWCAP2)
  120. # ifdef HAVE_GETAUXVAL
  121. cpu_features->has_armcrypto = (getauxval(AT_HWCAP2) & (1L << 0)) != 0;
  122. # elif defined(HAVE_ELF_AUX_INFO)
  123. {
  124. unsigned long buf;
  125. if (elf_aux_info(AT_HWCAP2, (void *) &buf, (int) sizeof buf) == 0) {
  126. cpu_features->has_armcrypto = (buf & (1L << 0)) != 0;
  127. }
  128. }
  129. # endif
  130. #endif
  131. return 0;
  132. }
  133. static void
  134. _cpuid(unsigned int cpu_info[4U], const unsigned int cpu_info_type)
  135. {
  136. #if defined(_MSC_VER) && \
  137. (defined(_M_X64) || defined(_M_AMD64) || defined(_M_IX86))
  138. __cpuid((int *) cpu_info, cpu_info_type);
  139. #elif defined(HAVE_CPUID)
  140. cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0;
  141. # ifdef __i386__
  142. __asm__ __volatile__(
  143. "pushfl; pushfl; "
  144. "popl %0; "
  145. "movl %0, %1; xorl %2, %0; "
  146. "pushl %0; "
  147. "popfl; pushfl; popl %0; popfl"
  148. : "=&r"(cpu_info[0]), "=&r"(cpu_info[1])
  149. : "i"(0x200000));
  150. if (((cpu_info[0] ^ cpu_info[1]) & 0x200000) == 0x0) {
  151. return; /* LCOV_EXCL_LINE */
  152. }
  153. # endif
  154. # ifdef __i386__
  155. __asm__ __volatile__("xchgl %%ebx, %k1; cpuid; xchgl %%ebx, %k1"
  156. : "=a"(cpu_info[0]), "=&r"(cpu_info[1]),
  157. "=c"(cpu_info[2]), "=d"(cpu_info[3])
  158. : "0"(cpu_info_type), "2"(0U));
  159. # elif defined(__x86_64__)
  160. __asm__ __volatile__("xchgq %%rbx, %q1; cpuid; xchgq %%rbx, %q1"
  161. : "=a"(cpu_info[0]), "=&r"(cpu_info[1]),
  162. "=c"(cpu_info[2]), "=d"(cpu_info[3])
  163. : "0"(cpu_info_type), "2"(0U));
  164. # else
  165. __asm__ __volatile__("cpuid"
  166. : "=a"(cpu_info[0]), "=b"(cpu_info[1]),
  167. "=c"(cpu_info[2]), "=d"(cpu_info[3])
  168. : "0"(cpu_info_type), "2"(0U));
  169. # endif
  170. #else
  171. (void) cpu_info_type;
  172. cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0;
  173. #endif
  174. }
  175. static int
  176. _sodium_runtime_intel_cpu_features(CPUFeatures * const cpu_features)
  177. {
  178. unsigned int cpu_info[4];
  179. uint32_t xcr0 = 0U;
  180. _cpuid(cpu_info, 0x0);
  181. if (cpu_info[0] == 0U) {
  182. return -1; /* LCOV_EXCL_LINE */
  183. }
  184. _cpuid(cpu_info, 0x00000001);
  185. #ifdef HAVE_EMMINTRIN_H
  186. cpu_features->has_sse2 = ((cpu_info[3] & CPUID_EDX_SSE2) != 0x0);
  187. #else
  188. cpu_features->has_sse2 = 0;
  189. #endif
  190. #ifdef HAVE_PMMINTRIN_H
  191. cpu_features->has_sse3 = ((cpu_info[2] & CPUID_ECX_SSE3) != 0x0);
  192. #else
  193. cpu_features->has_sse3 = 0;
  194. #endif
  195. #ifdef HAVE_TMMINTRIN_H
  196. cpu_features->has_ssse3 = ((cpu_info[2] & CPUID_ECX_SSSE3) != 0x0);
  197. #else
  198. cpu_features->has_ssse3 = 0;
  199. #endif
  200. #ifdef HAVE_SMMINTRIN_H
  201. cpu_features->has_sse41 = ((cpu_info[2] & CPUID_ECX_SSE41) != 0x0);
  202. #else
  203. cpu_features->has_sse41 = 0;
  204. #endif
  205. cpu_features->has_avx = 0;
  206. (void) xcr0;
  207. #ifdef HAVE_AVXINTRIN_H
  208. if ((cpu_info[2] & (CPUID_ECX_AVX | CPUID_ECX_XSAVE | CPUID_ECX_OSXSAVE)) ==
  209. (CPUID_ECX_AVX | CPUID_ECX_XSAVE | CPUID_ECX_OSXSAVE)) {
  210. xcr0 = 0U;
  211. # if defined(HAVE__XGETBV) || \
  212. (defined(_MSC_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) && _MSC_FULL_VER >= 160040219)
  213. xcr0 = (uint32_t) _xgetbv(0);
  214. # elif defined(_MSC_VER) && defined(_M_IX86)
  215. /*
  216. * Visual Studio documentation states that eax/ecx/edx don't need to
  217. * be preserved in inline assembly code. But that doesn't seem to
  218. * always hold true on Visual Studio 2010.
  219. */
  220. __asm {
  221. push eax
  222. push ecx
  223. push edx
  224. xor ecx, ecx
  225. _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
  226. mov xcr0, eax
  227. pop edx
  228. pop ecx
  229. pop eax
  230. }
  231. # elif defined(HAVE_AVX_ASM)
  232. __asm__ __volatile__(".byte 0x0f, 0x01, 0xd0" /* XGETBV */
  233. : "=a"(xcr0)
  234. : "c"((uint32_t) 0U)
  235. : "%edx");
  236. # endif
  237. if ((xcr0 & (XCR0_SSE | XCR0_AVX)) == (XCR0_SSE | XCR0_AVX)) {
  238. cpu_features->has_avx = 1;
  239. }
  240. }
  241. #endif
  242. cpu_features->has_avx2 = 0;
  243. #ifdef HAVE_AVX2INTRIN_H
  244. if (cpu_features->has_avx) {
  245. unsigned int cpu_info7[4];
  246. _cpuid(cpu_info7, 0x00000007);
  247. cpu_features->has_avx2 = ((cpu_info7[1] & CPUID_EBX_AVX2) != 0x0);
  248. }
  249. #endif
  250. cpu_features->has_avx512f = 0;
  251. #ifdef HAVE_AVX512FINTRIN_H
  252. if (cpu_features->has_avx2) {
  253. unsigned int cpu_info7[4];
  254. _cpuid(cpu_info7, 0x00000007);
  255. /* LCOV_EXCL_START */
  256. if ((cpu_info7[1] & CPUID_EBX_AVX512F) == CPUID_EBX_AVX512F &&
  257. (xcr0 & (XCR0_OPMASK | XCR0_ZMM_HI256 | XCR0_HI16_ZMM))
  258. == (XCR0_OPMASK | XCR0_ZMM_HI256 | XCR0_HI16_ZMM)) {
  259. cpu_features->has_avx512f = 1;
  260. }
  261. /* LCOV_EXCL_STOP */
  262. }
  263. #endif
  264. #ifdef HAVE_WMMINTRIN_H
  265. cpu_features->has_pclmul = ((cpu_info[2] & CPUID_ECX_PCLMUL) != 0x0);
  266. cpu_features->has_aesni = ((cpu_info[2] & CPUID_ECX_AESNI) != 0x0);
  267. #else
  268. cpu_features->has_pclmul = 0;
  269. cpu_features->has_aesni = 0;
  270. #endif
  271. #ifdef HAVE_RDRAND
  272. cpu_features->has_rdrand = ((cpu_info[2] & CPUID_ECX_RDRAND) != 0x0);
  273. #else
  274. cpu_features->has_rdrand = 0;
  275. #endif
  276. return 0;
  277. }
  278. int
  279. _sodium_runtime_get_cpu_features(void)
  280. {
  281. int ret = -1;
  282. ret &= _sodium_runtime_arm_cpu_features(&_cpu_features);
  283. ret &= _sodium_runtime_intel_cpu_features(&_cpu_features);
  284. _cpu_features.initialized = 1;
  285. return ret;
  286. }
  287. int
  288. sodium_runtime_has_neon(void)
  289. {
  290. return _cpu_features.has_neon;
  291. }
  292. int
  293. sodium_runtime_has_armcrypto(void)
  294. {
  295. return _cpu_features.has_armcrypto;
  296. }
  297. int
  298. sodium_runtime_has_sse2(void)
  299. {
  300. return _cpu_features.has_sse2;
  301. }
  302. int
  303. sodium_runtime_has_sse3(void)
  304. {
  305. return _cpu_features.has_sse3;
  306. }
  307. int
  308. sodium_runtime_has_ssse3(void)
  309. {
  310. return _cpu_features.has_ssse3;
  311. }
  312. int
  313. sodium_runtime_has_sse41(void)
  314. {
  315. return _cpu_features.has_sse41;
  316. }
  317. int
  318. sodium_runtime_has_avx(void)
  319. {
  320. return _cpu_features.has_avx;
  321. }
  322. int
  323. sodium_runtime_has_avx2(void)
  324. {
  325. return _cpu_features.has_avx2;
  326. }
  327. int
  328. sodium_runtime_has_avx512f(void)
  329. {
  330. return _cpu_features.has_avx512f;
  331. }
  332. int
  333. sodium_runtime_has_pclmul(void)
  334. {
  335. return _cpu_features.has_pclmul;
  336. }
  337. int
  338. sodium_runtime_has_aesni(void)
  339. {
  340. return _cpu_features.has_aesni;
  341. }
  342. int
  343. sodium_runtime_has_rdrand(void)
  344. {
  345. return _cpu_features.has_rdrand;
  346. }