Crypto++  7.0
Free C++ class library of cryptographic schemes
cpu.cpp
1 // cpu.cpp - originally written and placed in the public domain by Wei Dai
2 
3 #include "pch.h"
4 #include "config.h"
5 
6 #ifndef EXCEPTION_EXECUTE_HANDLER
7 # define EXCEPTION_EXECUTE_HANDLER 1
8 #endif
9 
10 #ifndef CRYPTOPP_IMPORTS
11 
12 #include "cpu.h"
13 #include "misc.h"
14 #include "stdcpp.h"
15 
16 #ifdef _AIX
17 # include <sys/systemcfg.h>
18 #endif
19 
20 #ifdef __linux__
21 # include <unistd.h>
22 #endif
23 
24 // Capability queries, requires Glibc 2.16, http://lwn.net/Articles/519085/
25 // CRYPTOPP_GLIBC_VERSION not used because config.h is missing <feature.h>
26 #if (((__GLIBC__ * 100) + __GLIBC_MINOR__) >= 216)
27 # define CRYPTOPP_GETAUXV_AVAILABLE 1
28 #endif
29 
30 #if CRYPTOPP_GETAUXV_AVAILABLE
31 # include <sys/auxv.h>
32 #else
33 #ifndef AT_HWCAP
34 # define AT_HWCAP 16
35 #endif
36 #ifndef AT_HWCAP2
37 # define AT_HWCAP2 26
38 #endif
39 unsigned long int getauxval(unsigned long int) { return 0; }
40 #endif
41 
42 #if defined(__APPLE__) && (defined(__aarch64__) || defined(__POWERPC__))
43 # include <sys/utsname.h>
44 #endif
45 
46 // The cpu-features header and source file are located in $ANDROID_NDK_ROOT/sources/android/cpufeatures
47 // setenv-android.sh will copy the header and source file into PWD and the makefile will build it in place.
48 #if defined(__ANDROID__)
49 # include "cpu-features.h"
50 #endif
51 
52 #ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
53 # include <signal.h>
54 # include <setjmp.h>
55 #endif
56 
57 NAMESPACE_BEGIN(CryptoPP)
58 
59 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
60 extern "C" {
61  typedef void (*SigHandler)(int);
62 }
63 
64 extern "C"
65 {
66  static jmp_buf s_jmpNoCPUID;
67  static void SigIllHandlerCPUID(int unused)
68  {
69  CRYPTOPP_UNUSED(unused);
70  longjmp(s_jmpNoCPUID, 1);
71  }
72 }
73 #endif // Not CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
74 
75 // *************************** IA-32 CPUs ***************************
76 
77 #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
78 
79 extern bool CPU_ProbeSSE2();
80 
81 #if _MSC_VER >= 1600
82 
83 inline bool CpuId(word32 func, word32 subfunc, word32 output[4])
84 {
85  __cpuidex((int *)output, func, subfunc);
86  return true;
87 }
88 
89 #elif _MSC_VER >= 1400 && CRYPTOPP_BOOL_X64
90 
91 inline bool CpuId(word32 func, word32 subfunc, word32 output[4])
92 {
93  if (subfunc != 0)
94  return false;
95 
96  __cpuid((int *)output, func);
97  return true;
98 }
99 
100 #else
101 
102 // Borland/Embarcadero and Issue 498
103 // cpu.cpp (131): E2211 Inline assembly not allowed in inline and template functions
104 bool CpuId(word32 func, word32 subfunc, word32 output[4])
105 {
106 #if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) || defined(__BORLANDC__)
107  __try
108  {
109  // Borland/Embarcadero and Issue 500
110  // Local variables for cpuid output
111  word32 a, b, c, d;
112  __asm
113  {
114  mov eax, func
115  mov ecx, subfunc
116  cpuid
117  mov [a], eax
118  mov [b], ebx
119  mov [c], ecx
120  mov [d], edx
121  }
122  output[0] = a;
123  output[1] = b;
124  output[2] = c;
125  output[3] = d;
126  }
127  // GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION
128  __except (EXCEPTION_EXECUTE_HANDLER)
129  {
130  return false;
131  }
132 
133  // func = 0 returns the highest basic function understood in EAX. If the CPU does
134  // not return non-0, then it is mostly useless. The code below converts basic
135  // function value to a true/false return value.
136  if(func == 0)
137  return output[0] != 0;
138 
139  return true;
140 #else
141  // longjmp and clobber warnings. Volatile is required.
142  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
143  volatile bool result = true;
144 
145  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerCPUID);
146  if (oldHandler == SIG_ERR)
147  return false;
148 
149 # ifndef __MINGW32__
150  volatile sigset_t oldMask;
151  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask) != 0)
152  return false;
153 # endif
154 
155  if (setjmp(s_jmpNoCPUID))
156  result = false;
157  else
158  {
159  asm volatile
160  (
161  // save ebx in case -fPIC is being used
162  // TODO: this might need an early clobber on EDI.
163 # if CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
164  "pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx"
165 # else
166  "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
167 # endif
168  : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3])
169  : "a" (func), "c" (subfunc)
170  : "cc"
171  );
172  }
173 
174 # ifndef __MINGW32__
175  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
176 # endif
177 
178  signal(SIGILL, oldHandler);
179  return result;
180 #endif
181 }
182 
183 #endif
184 
185 bool CRYPTOPP_SECTION_INIT g_x86DetectionDone = false;
186 bool CRYPTOPP_SECTION_INIT g_hasSSE2 = false;
187 bool CRYPTOPP_SECTION_INIT g_hasSSSE3 = false;
188 bool CRYPTOPP_SECTION_INIT g_hasSSE41 = false;
189 bool CRYPTOPP_SECTION_INIT g_hasSSE42 = false;
190 bool CRYPTOPP_SECTION_INIT g_hasAESNI = false;
191 bool CRYPTOPP_SECTION_INIT g_hasCLMUL = false;
192 bool CRYPTOPP_SECTION_INIT g_hasADX = false;
193 bool CRYPTOPP_SECTION_INIT g_hasSHA = false;
194 bool CRYPTOPP_SECTION_INIT g_hasRDRAND = false;
195 bool CRYPTOPP_SECTION_INIT g_hasRDSEED = false;
196 bool CRYPTOPP_SECTION_INIT g_isP4 = false;
197 bool CRYPTOPP_SECTION_INIT g_hasPadlockRNG = false;
198 bool CRYPTOPP_SECTION_INIT g_hasPadlockACE = false;
199 bool CRYPTOPP_SECTION_INIT g_hasPadlockACE2 = false;
200 bool CRYPTOPP_SECTION_INIT g_hasPadlockPHE = false;
201 bool CRYPTOPP_SECTION_INIT g_hasPadlockPMM = false;
202 word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
203 
204 static inline bool IsIntel(const word32 output[4])
205 {
206  // This is the "GenuineIntel" string
207  return (output[1] /*EBX*/ == 0x756e6547) &&
208  (output[2] /*ECX*/ == 0x6c65746e) &&
209  (output[3] /*EDX*/ == 0x49656e69);
210 }
211 
212 static inline bool IsAMD(const word32 output[4])
213 {
214  // This is the "AuthenticAMD" string. Some early K5's can return "AMDisbetter!"
215  return (output[1] /*EBX*/ == 0x68747541) &&
216  (output[2] /*ECX*/ == 0x444D4163) &&
217  (output[3] /*EDX*/ == 0x69746E65);
218 }
219 
220 static inline bool IsVIA(const word32 output[4])
221 {
222  // This is the "CentaurHauls" string. Some non-PadLock's can return "VIA VIA VIA "
223  return (output[1] /*EBX*/ == 0x746e6543) &&
224  (output[2] /*ECX*/ == 0x736c7561) &&
225  (output[3] /*EDX*/ == 0x48727561);
226 }
227 
228 void DetectX86Features()
229 {
230  // Coverity finding CID 171239...
231  word32 cpuid0[4]={0}, cpuid1[4]={0}, cpuid2[4]={0};
232  if (!CpuId(0, 0, cpuid0))
233  return;
234  if (!CpuId(1, 0, cpuid1))
235  return;
236 
237  // cpuid1[2] & (1 << 27) is XSAVE/XRESTORE and signals OS support for SSE; use it to avoid probes.
238  // See http://github.com/weidai11/cryptopp/issues/511 and http://stackoverflow.com/a/22521619/608639
239  if ((cpuid1[3] & (1 << 26)) != 0)
240  g_hasSSE2 = ((cpuid1[2] & (1 << 27)) != 0) || CPU_ProbeSSE2();
241 
242  g_hasSSSE3 = g_hasSSE2 && ((cpuid1[2] & (1<< 9)) != 0);
243  g_hasSSE41 = g_hasSSE2 && ((cpuid1[2] & (1<<19)) != 0);
244  g_hasSSE42 = g_hasSSE2 && ((cpuid1[2] & (1<<20)) != 0);
245  g_hasAESNI = g_hasSSE2 && ((cpuid1[2] & (1<<25)) != 0);
246  g_hasCLMUL = g_hasSSE2 && ((cpuid1[2] & (1<< 1)) != 0);
247 
248  if (IsIntel(cpuid0))
249  {
250  CRYPTOPP_CONSTANT(RDRAND_FLAG = (1 << 30))
251  CRYPTOPP_CONSTANT(RDSEED_FLAG = (1 << 18))
252  CRYPTOPP_CONSTANT( ADX_FLAG = (1 << 19))
253  CRYPTOPP_CONSTANT( SHA_FLAG = (1 << 29))
254 
255  g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf;
256  g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1);
257  g_hasRDRAND = (cpuid1[2] /*ECX*/ & RDRAND_FLAG) != 0;
258 
259  if (cpuid0[0] /*EAX*/ >= 7)
260  {
261  if (CpuId(7, 0, cpuid2))
262  {
263  g_hasRDSEED = (cpuid2[1] /*EBX*/ & RDSEED_FLAG) != 0;
264  g_hasADX = (cpuid2[1] /*EBX*/ & ADX_FLAG) != 0;
265  g_hasSHA = (cpuid2[1] /*EBX*/ & SHA_FLAG) != 0;
266  }
267  }
268  }
269  else if (IsAMD(cpuid0))
270  {
271  CRYPTOPP_CONSTANT(RDRAND_FLAG = (1 << 30))
272  CRYPTOPP_CONSTANT(RDSEED_FLAG = (1 << 18))
273  CRYPTOPP_CONSTANT( ADX_FLAG = (1 << 19))
274  CRYPTOPP_CONSTANT( SHA_FLAG = (1 << 29))
275 
276  CpuId(0x80000005, 0, cpuid2);
277  g_cacheLineSize = GETBYTE(cpuid2[2], 0);
278  g_hasRDRAND = (cpuid1[2] /*ECX*/ & RDRAND_FLAG) != 0;
279 
280  if (cpuid0[0] /*EAX*/ >= 7)
281  {
282  if (CpuId(7, 0, cpuid2))
283  {
284  g_hasRDSEED = (cpuid2[1] /*EBX*/ & RDSEED_FLAG) != 0;
285  g_hasADX = (cpuid2[1] /*EBX*/ & ADX_FLAG) != 0;
286  g_hasSHA = (cpuid2[1] /*EBX*/ & SHA_FLAG) != 0;
287  }
288  }
289  }
290  else if (IsVIA(cpuid0))
291  {
292  CRYPTOPP_CONSTANT( RNG_FLAGS = (0x3 << 2))
293  CRYPTOPP_CONSTANT( ACE_FLAGS = (0x3 << 6))
294  CRYPTOPP_CONSTANT(ACE2_FLAGS = (0x3 << 8))
295  CRYPTOPP_CONSTANT( PHE_FLAGS = (0x3 << 10))
296  CRYPTOPP_CONSTANT( PMM_FLAGS = (0x3 << 12))
297 
298  CpuId(0xC0000000, 0, cpuid2);
299  if (cpuid2[0] >= 0xC0000001)
300  {
301  // Extended features available
302  CpuId(0xC0000001, 0, cpuid2);
303  g_hasPadlockRNG = (cpuid2[3] /*EDX*/ & RNG_FLAGS) != 0;
304  g_hasPadlockACE = (cpuid2[3] /*EDX*/ & ACE_FLAGS) != 0;
305  g_hasPadlockACE2 = (cpuid2[3] /*EDX*/ & ACE2_FLAGS) != 0;
306  g_hasPadlockPHE = (cpuid2[3] /*EDX*/ & PHE_FLAGS) != 0;
307  g_hasPadlockPMM = (cpuid2[3] /*EDX*/ & PMM_FLAGS) != 0;
308  }
309  }
310 
311  if (g_cacheLineSize == 0)
312  g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
313 
314  *const_cast<volatile bool*>(&g_x86DetectionDone) = true;
315 }
316 
317 // *************************** ARM-32, Aarch32 and Aarch64 ***************************
318 
319 #elif (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64)
320 
321 bool CRYPTOPP_SECTION_INIT g_ArmDetectionDone = false;
322 bool CRYPTOPP_SECTION_INIT g_hasNEON = false;
323 bool CRYPTOPP_SECTION_INIT g_hasPMULL = false;
324 bool CRYPTOPP_SECTION_INIT g_hasCRC32 = false;
325 bool CRYPTOPP_SECTION_INIT g_hasAES = false;
326 bool CRYPTOPP_SECTION_INIT g_hasSHA1 = false;
327 bool CRYPTOPP_SECTION_INIT g_hasSHA2 = false;
328 word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
329 
330 // ARM does not have an unprivliged equivalent to CPUID on IA-32. We have to jump through some
331 // hoops to detect features on a wide array of platforms. Our strategy is two part. First,
332 // attempt to *Query* the OS for a feature, like using getauxval on Linux. If that fails,
333 // then *Probe* the cpu executing an instruction and an observe a SIGILL if unsupported.
334 // The probes are in source files where compilation options like -march=armv8-a+crc make
335 // intrinsics available. They are expensive when compared to a standard OS feature query.
336 // Always perform the feature quesry first. For Linux see
337 // http://sourceware.org/ml/libc-help/2017-08/msg00012.html
338 // Avoid probes on Apple platforms because Apple's signal handling for SIGILLs appears broken.
339 // We are trying to figure out a way to feature test without probes. Also see
340 // http://stackoverflow.com/a/11197770/608639 and
341 // http://gist.github.com/erkanyildiz/390a480f27e86f8cd6ba
342 
343 extern bool CPU_ProbeNEON();
344 extern bool CPU_ProbeCRC32();
345 extern bool CPU_ProbeAES();
346 extern bool CPU_ProbeSHA1();
347 extern bool CPU_ProbeSHA2();
348 extern bool CPU_ProbePMULL();
349 
350 #ifndef HWCAP_ASIMD
351 # define HWCAP_ASIMD (1 << 1)
352 #endif
353 #ifndef HWCAP_ARM_NEON
354 # define HWCAP_ARM_NEON 4096
355 #endif
356 #ifndef HWCAP_CRC32
357 # define HWCAP_CRC32 (1 << 7)
358 #endif
359 #ifndef HWCAP2_CRC32
360 # define HWCAP2_CRC32 (1 << 4)
361 #endif
362 #ifndef HWCAP_PMULL
363 # define HWCAP_PMULL (1 << 4)
364 #endif
365 #ifndef HWCAP2_PMULL
366 # define HWCAP2_PMULL (1 << 1)
367 #endif
368 #ifndef HWCAP_AES
369 # define HWCAP_AES (1 << 3)
370 #endif
371 #ifndef HWCAP2_AES
372 # define HWCAP2_AES (1 << 0)
373 #endif
374 #ifndef HWCAP_SHA1
375 # define HWCAP_SHA1 (1 << 5)
376 #endif
377 #ifndef HWCAP_SHA2
378 # define HWCAP_SHA2 (1 << 6)
379 #endif
380 #ifndef HWCAP2_SHA1
381 # define HWCAP2_SHA1 (1 << 2)
382 #endif
383 #ifndef HWCAP2_SHA2
384 # define HWCAP2_SHA2 (1 << 3)
385 #endif
386 
387 inline bool CPU_QueryNEON()
388 {
389 #if defined(__ANDROID__) && defined(__aarch64__)
390  if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&
391  ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_ASIMD) != 0))
392  return true;
393 #elif defined(__ANDROID__) && defined(__arm__)
394  if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&
395  ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0))
396  return true;
397 #elif defined(__linux__) && defined(__aarch64__)
398  if ((getauxval(AT_HWCAP) & HWCAP_ASIMD) != 0)
399  return true;
400 #elif defined(__linux__) && defined(__aarch32__)
401  if ((getauxval(AT_HWCAP2) & HWCAP2_ASIMD) != 0)
402  return true;
403 #elif defined(__linux__) && defined(__arm__)
404  if ((getauxval(AT_HWCAP) & HWCAP_ARM_NEON) != 0)
405  return true;
406 #elif defined(__APPLE__) && defined(__aarch64__)
407  // Core feature set for Aarch32 and Aarch64.
408  return true;
409 #endif
410  return false;
411 }
412 
413 inline bool CPU_QueryCRC32()
414 {
415 #if defined(__ANDROID__) && defined(__aarch64__)
416  if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&
417  ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_CRC32) != 0))
418  return true;
419 #elif defined(__ANDROID__) && defined(__aarch32__)
420  if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&
421  ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_CRC32) != 0))
422  return true;
423 #elif defined(__linux__) && defined(__aarch64__)
424  if ((getauxval(AT_HWCAP) & HWCAP_CRC32) != 0)
425  return true;
426 #elif defined(__linux__) && defined(__aarch32__)
427  if ((getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0)
428  return true;
429 #elif defined(__APPLE__) && defined(__aarch64__)
430  // No compiler support. CRC intrinsics result in a failed compiled.
431  return false;
432 #endif
433  return false;
434 }
435 
436 inline bool CPU_QueryPMULL()
437 {
438 #if defined(__ANDROID__) && defined(__aarch64__)
439  if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&
440  ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_PMULL) != 0))
441  return true;
442 #elif defined(__ANDROID__) && defined(__aarch32__)
443  if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&
444  ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_PMULL) != 0))
445  return true;
446 #elif defined(__linux__) && defined(__aarch64__)
447  if ((getauxval(AT_HWCAP) & HWCAP_PMULL) != 0)
448  return true;
449 #elif defined(__linux__) && defined(__aarch32__)
450  if ((getauxval(AT_HWCAP2) & HWCAP2_PMULL) != 0)
451  return true;
452 #elif defined(__APPLE__) && defined(__aarch64__)
453  // No compiler support. PMULL intrinsics result in a failed compiled.
454  return false;
455 #endif
456  return false;
457 }
458 
459 inline bool CPU_QueryAES()
460 {
461 #if defined(__ANDROID__) && defined(__aarch64__)
462  if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&
463  ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_AES) != 0))
464  return true;
465 #elif defined(__ANDROID__) && defined(__aarch32__)
466  if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&
467  ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_AES) != 0))
468  return true;
469 #elif defined(__linux__) && defined(__aarch64__)
470  if ((getauxval(AT_HWCAP) & HWCAP_AES) != 0)
471  return true;
472 #elif defined(__linux__) && defined(__aarch32__)
473  if ((getauxval(AT_HWCAP2) & HWCAP2_AES) != 0)
474  return true;
475 #elif defined(__APPLE__) && defined(__aarch64__)
476  // http://stackoverflow.com/questions/45637888/how-to-determine-armv8-features-at-runtime-on-ios
477  struct utsname systemInfo;
478  systemInfo.machine[0] = '\0';
479  uname(&systemInfo);
480 
481  // The machine strings below are known ARM8 devices
482  std::string machine(systemInfo.machine);
483  if (machine.substr(0, 7) == "iPhone6" || machine.substr(0, 7) == "iPhone7" ||
484  machine.substr(0, 7) == "iPhone8" || machine.substr(0, 7) == "iPhone9" ||
485  machine.substr(0, 5) == "iPad4" || machine.substr(0, 5) == "iPad5" ||
486  machine.substr(0, 5) == "iPad6" || machine.substr(0, 5) == "iPad7")
487  {
488  return true;
489  }
490 #endif
491  return false;
492 }
493 
494 inline bool CPU_QuerySHA1()
495 {
496 #if defined(__ANDROID__) && defined(__aarch64__)
497  if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&
498  ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA1) != 0))
499  return true;
500 #elif defined(__ANDROID__) && defined(__aarch32__)
501  if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&
502  ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA1) != 0))
503  return true;
504 #elif defined(__linux__) && defined(__aarch64__)
505  if ((getauxval(AT_HWCAP) & HWCAP_SHA1) != 0)
506  return true;
507 #elif defined(__linux__) && defined(__aarch32__)
508  if ((getauxval(AT_HWCAP2) & HWCAP2_SHA1) != 0)
509  return true;
510 #elif defined(__APPLE__) && defined(__aarch64__)
511  // http://stackoverflow.com/questions/45637888/how-to-determine-armv8-features-at-runtime-on-ios
512  struct utsname systemInfo;
513  systemInfo.machine[0] = '\0';
514  uname(&systemInfo);
515 
516  // The machine strings below are known ARM8 devices
517  std::string machine(systemInfo.machine);
518  if (machine.substr(0, 7) == "iPhone6" || machine.substr(0, 7) == "iPhone7" ||
519  machine.substr(0, 7) == "iPhone8" || machine.substr(0, 7) == "iPhone9" ||
520  machine.substr(0, 5) == "iPad4" || machine.substr(0, 5) == "iPad5" ||
521  machine.substr(0, 5) == "iPad6" || machine.substr(0, 5) == "iPad7")
522  {
523  return true;
524  }
525 #endif
526  return false;
527 }
528 
529 inline bool CPU_QuerySHA2()
530 {
531 #if defined(__ANDROID__) && defined(__aarch64__)
532  if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&
533  ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA2) != 0))
534  return true;
535 #elif defined(__ANDROID__) && defined(__aarch32__)
536  if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&
537  ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA2) != 0))
538  return true;
539 #elif defined(__linux__) && defined(__aarch64__)
540  if ((getauxval(AT_HWCAP) & HWCAP_SHA2) != 0)
541  return true;
542 #elif defined(__linux__) && defined(__aarch32__)
543  if ((getauxval(AT_HWCAP2) & HWCAP2_SHA2) != 0)
544  return true;
545 #elif defined(__APPLE__) && defined(__aarch64__)
546  // http://stackoverflow.com/questions/45637888/how-to-determine-armv8-features-at-runtime-on-ios
547  struct utsname systemInfo;
548  systemInfo.machine[0] = '\0';
549  uname(&systemInfo);
550 
551  // The machine strings below are known ARM8 devices
552  std::string machine(systemInfo.machine);
553  if (machine.substr(0, 7) == "iPhone6" || machine.substr(0, 7) == "iPhone7" ||
554  machine.substr(0, 7) == "iPhone8" || machine.substr(0, 7) == "iPhone9" ||
555  machine.substr(0, 5) == "iPad4" || machine.substr(0, 5) == "iPad5" ||
556  machine.substr(0, 5) == "iPad6" || machine.substr(0, 5) == "iPad7")
557  {
558  return true;
559  }
560 #endif
561  return false;
562 }
563 
564 void DetectArmFeatures()
565 {
566  // The CPU_ProbeXXX's return false for OSes which
567  // can't tolerate SIGILL-based probes
568  g_hasNEON = CPU_QueryNEON() || CPU_ProbeNEON();
569  g_hasCRC32 = CPU_QueryCRC32() || CPU_ProbeCRC32();
570  g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL();
571  g_hasAES = CPU_QueryAES() || CPU_ProbeAES();
572  g_hasSHA1 = CPU_QuerySHA1() || CPU_ProbeSHA1();
573  g_hasSHA2 = CPU_QuerySHA2() || CPU_ProbeSHA2();
574 
575 #if defined(__linux__) && defined(_SC_LEVEL1_DCACHE_LINESIZE)
576  // Glibc does not implement on some platforms. The runtime returns 0 instead of error.
577  // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/sysconf.c
578  int cacheLineSize = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
579  if (cacheLineSize > 0)
580  g_cacheLineSize = cacheLineSize;
581 #endif
582 
583  *const_cast<volatile bool*>(&g_ArmDetectionDone) = true;
584 }
585 
586 // *************************** PowerPC and PowerPC64 ***************************
587 
588 #elif (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64)
589 
590 bool CRYPTOPP_SECTION_INIT g_PowerpcDetectionDone = false;
591 bool CRYPTOPP_SECTION_INIT g_hasAltivec = false;
592 bool CRYPTOPP_SECTION_INIT g_hasPower7 = false;
593 bool CRYPTOPP_SECTION_INIT g_hasPower8 = false;
594 bool CRYPTOPP_SECTION_INIT g_hasAES = false;
595 bool CRYPTOPP_SECTION_INIT g_hasSHA256 = false;
596 bool CRYPTOPP_SECTION_INIT g_hasSHA512 = false;
597 word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
598 
599 extern bool CPU_ProbeAltivec();
600 extern bool CPU_ProbePower7();
601 extern bool CPU_ProbePower8();
602 extern bool CPU_ProbeAES();
603 extern bool CPU_ProbeSHA256();
604 extern bool CPU_ProbeSHA512();
605 
606 #ifndef PPC_FEATURE_HAS_ALTIVEC
607 # define PPC_FEATURE_HAS_ALTIVEC 0x10000000
608 #endif
609 #ifndef PPC_FEATURE_ARCH_2_06
610 # define PPC_FEATURE_ARCH_2_06 0x00000100
611 #endif
612 #ifndef PPC_FEATURE2_ARCH_2_07
613 # define PPC_FEATURE2_ARCH_2_07 0x80000000
614 #endif
615 #ifndef PPC_FEATURE2_VEC_CRYPTO
616 # define PPC_FEATURE2_VEC_CRYPTO 0x02000000
617 #endif
618 
619 inline bool CPU_QueryAltivec()
620 {
621 #if defined(__linux__)
622  if ((getauxval(AT_HWCAP) & PPC_FEATURE_HAS_ALTIVEC) != 0)
623  return true;
624 #elif defined(_AIX)
625  if (__power_vmx() != 0)
626  return true;
627 #elif defined(__APPLE__) && defined(__POWERPC__)
628  // http://stackoverflow.com/questions/45637888/how-to-determine-armv8-features-at-runtime-on-ios
629  struct utsname systemInfo;
630  systemInfo.machine[0] = '\0';
631  uname(&systemInfo);
632 
633  // The machine strings below are known PPC machines
634  std::string machine(systemInfo.machine);
635  if (machine.substr(0, 15) == "Power Macintosh")
636  {
637  return true;
638  }
639 #endif
640  return false;
641 }
642 
643 inline bool CPU_QueryPower7()
644 {
645  // Power7 and ISA 2.06
646 #if defined(__linux__)
647  if ((getauxval(AT_HWCAP) & PPC_FEATURE_ARCH_2_06) != 0)
648  return true;
649 #elif defined(_AIX)
650  if (__power_7_andup() != 0)
651  return true;
652 #endif
653  return false;
654 }
655 
656 inline bool CPU_QueryPower8()
657 {
658  // Power8 and ISA 2.07 provide in-core crypto.
659 #if defined(__linux__)
660  if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_2_07) != 0)
661  return true;
662 #elif defined(_AIX)
663  if (__power_8_andup() != 0)
664  return true;
665 #endif
666  return false;
667 }
668 
669 inline bool CPU_QueryAES()
670 {
671  // Power8 and ISA 2.07 provide in-core crypto. Glibc
672  // 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO.
673 #if defined(__linux__)
674  if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0)
675  return true;
676 #elif defined(_AIX)
677  if (__power_8_andup() != 0)
678  return true;
679 #endif
680  return false;
681 }
682 
683 inline bool CPU_QuerySHA256()
684 {
685  // Power8 and ISA 2.07 provide in-core crypto. Glibc
686  // 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO.
687 #if defined(__linux__)
688  if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0)
689  return true;
690 #elif defined(_AIX)
691  if (__power_8_andup() != 0)
692  return true;
693 #endif
694  return false;
695 }
696 inline bool CPU_QuerySHA512()
697 {
698  // Power8 and ISA 2.07 provide in-core crypto. Glibc
699  // 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO.
700 #if defined(__linux__)
701  if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0)
702  return true;
703 #elif defined(_AIX)
704  if (__power_8_andup() != 0)
705  return true;
706 #endif
707  return false;
708 }
709 
710 void DetectPowerpcFeatures()
711 {
712  // The CPU_ProbeXXX's return false for OSes which
713  // can't tolerate SIGILL-based probes, like Apple
714  g_hasAltivec = CPU_QueryAltivec() || CPU_ProbeAltivec();
715  g_hasPower7 = CPU_QueryPower7() || CPU_ProbePower7();
716  g_hasPower8 = CPU_QueryPower8() || CPU_ProbePower8();
717  //g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL();
718  g_hasAES = CPU_QueryAES() || CPU_ProbeAES();
719  g_hasSHA256 = CPU_QuerySHA256() || CPU_ProbeSHA256();
720  g_hasSHA512 = CPU_QuerySHA512() || CPU_ProbeSHA512();
721 
722 #if defined(_AIX) && defined(SC_L1C_DLS)
723  // /usr/include/sys/systemcfg.h
724  int cacheLineSize = getsystemcfg(SC_L1C_DLS);
725  if (cacheLineSize > 0)
726  g_cacheLineSize = cacheLineSize;
727 #elif defined(__linux__) && defined(_SC_LEVEL1_DCACHE_LINESIZE)
728  // Glibc does not implement on some platforms. The runtime returns 0 instead of error.
729  // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/sysconf.c
730  int cacheLineSize = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
731  if (cacheLineSize > 0)
732  g_cacheLineSize = cacheLineSize;
733 #endif
734 
735  *const_cast<volatile bool*>(&g_PowerpcDetectionDone) = true;
736 }
737 
738 #endif
739 NAMESPACE_END
740 
741 // *************************** C++ Static Initialization ***************************
742 
743 ANONYMOUS_NAMESPACE_BEGIN
744 
745 class InitCpu
746 {
747 public:
748  InitCpu()
749  {
750 #if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
751  CryptoPP::DetectX86Features();
752 #elif CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64
753  CryptoPP::DetectArmFeatures();
754 #elif CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64
755  CryptoPP::DetectPowerpcFeatures();
756 #endif
757  }
758 };
759 
760 // This is not really needed because HasSSE() and friends can dynamically initialize.
761 // Everything depends on CPU features so we initialize it once at load time.
762 // Dynamic initialization will be used if init priorities are not available.
763 
764 #if HAVE_GCC_INIT_PRIORITY
765  const InitCpu s_init __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 10))) = InitCpu();
766 #elif HAVE_MSC_INIT_PRIORITY
767  #pragma warning(disable: 4075)
768  #pragma init_seg(".CRT$XCU")
769  const InitCpu s_init;
770  #pragma warning(default: 4075)
771 #else
772  const InitCpu s_init;
773 #endif
774 
775 ANONYMOUS_NAMESPACE_END
776 
777 #endif // CRYPTOPP_IMPORTS
Utility functions for the Crypto++ library.
Library configuration file.
Common C++ header files.
Precompiled header file.
Functions for CPU features and intrinsics.
Crypto++ library namespace.