Line | Count | Source (jump to first uncovered line) |
1 | | // cpu.cpp - originally written and placed in the public domain by Wei Dai |
2 | | // modified by Jeffrey Walton and the community over the years. |
3 | | |
4 | | #include "pch.h" |
5 | | #include "config.h" |
6 | | |
7 | | #ifndef EXCEPTION_EXECUTE_HANDLER |
8 | | # define EXCEPTION_EXECUTE_HANDLER 1 |
9 | | #endif |
10 | | |
11 | | #ifndef CRYPTOPP_IMPORTS |
12 | | |
13 | | #include "cpu.h" |
14 | | #include "misc.h" |
15 | | #include "stdcpp.h" |
16 | | |
17 | | // For _xgetbv on Microsoft 32-bit and 64-bit Intel platforms |
18 | | // https://github.com/weidai11/cryptopp/issues/972 |
19 | | #if (CRYPTOPP_MSC_VERSION >= 1600) && (defined(_M_IX86) || defined(_M_X64)) |
20 | | # include <immintrin.h> |
21 | | #endif |
22 | | |
23 | | // For IsProcessorFeaturePresent on Microsoft Arm64 platforms, |
24 | | // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent |
25 | | #if defined(_WIN32) && defined(_M_ARM64) |
26 | | # include <Windows.h> |
27 | | # include <processthreadsapi.h> |
28 | | #endif |
29 | | |
30 | | #ifdef _AIX |
31 | | # include <sys/systemcfg.h> |
32 | | #endif |
33 | | |
34 | | #ifdef __linux__ |
35 | | # include <unistd.h> |
36 | | #endif |
37 | | |
38 | | // Capability queries, requires Glibc 2.16, http://lwn.net/Articles/519085/ |
39 | | // CRYPTOPP_GLIBC_VERSION not used because config.h is missing <feature.h> |
40 | | #if (((__GLIBC__ * 100) + __GLIBC_MINOR__) >= 216) |
41 | | # define CRYPTOPP_GETAUXV_AVAILABLE 1 |
42 | | #endif |
43 | | |
44 | | #if CRYPTOPP_GETAUXV_AVAILABLE |
45 | | # include <sys/auxv.h> |
46 | | #else |
47 | | #ifndef AT_HWCAP |
48 | | # define AT_HWCAP 16 |
49 | | #endif |
50 | | #ifndef AT_HWCAP2 |
51 | | # define AT_HWCAP2 26 |
52 | | #endif |
53 | | unsigned long int getauxval(unsigned long int) { return 0; } |
54 | | #endif |
55 | | |
56 | | #if defined(__APPLE__) |
57 | | # include <sys/utsname.h> |
58 | | # include <sys/sysctl.h> |
59 | | #endif |
60 | | |
61 | | // FreeBSD headers are giving us trouble... |
62 | | // https://github.com/weidai11/cryptopp/pull/1029 |
63 | | #if defined(__FreeBSD__) |
64 | | # include <sys/auxv.h> |
65 | | # include <sys/elf_common.h> |
66 | | #endif |
67 | | |
68 | | // The cpu-features header and source file are located in |
69 | | // "$ANDROID_NDK_ROOT/sources/android/cpufeatures". |
70 | | // setenv-android.sh will copy the header and source file |
71 | | // into PWD and the makefile will build it in place. |
72 | | #if defined(__ANDROID__) |
73 | | # include "cpu-features.h" |
74 | | #endif |
75 | | |
76 | | #ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY |
77 | | # include <signal.h> |
78 | | # include <setjmp.h> |
79 | | #endif |
80 | | |
81 | | // Required by Visual Studio 2008 and below and Clang on Windows. |
82 | | // Use it for all MSVC-compatible compilers. |
83 | | // XGETBV64 and CPUID64 are in x64dll.asm. |
84 | | #if defined(_M_X64) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) |
85 | | extern "C" unsigned long long __fastcall XGETBV64(unsigned int); |
86 | | extern "C" unsigned long long __fastcall CPUID64(unsigned int, unsigned int, unsigned int*); |
87 | | #endif |
88 | | |
89 | | #ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY |
90 | | extern "C" { |
91 | | typedef void (*SigHandler)(int); |
92 | | } |
93 | | |
94 | | extern "C" |
95 | | { |
96 | | static jmp_buf s_jmpNoCPUID; |
97 | | static void SigIllHandler(int) |
98 | 0 | { |
99 | 0 | longjmp(s_jmpNoCPUID, 1); |
100 | 0 | } |
101 | | } |
102 | | #endif // CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY |
103 | | |
104 | | ANONYMOUS_NAMESPACE_BEGIN |
105 | | |
106 | | #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) |
107 | | |
108 | | using CryptoPP::word32; |
109 | | |
110 | | inline bool IsIntel(const word32 output[4]) |
111 | 10 | { |
112 | | // This is the "GenuineIntel" string |
113 | 10 | return (output[1] /*EBX*/ == 0x756e6547) && |
114 | 10 | (output[2] /*ECX*/ == 0x6c65746e) && |
115 | 10 | (output[3] /*EDX*/ == 0x49656e69); |
116 | 10 | } |
117 | | |
118 | | inline bool IsAMD(const word32 output[4]) |
119 | 10 | { |
120 | | // This is the "AuthenticAMD" string. |
121 | 10 | return ((output[1] /*EBX*/ == 0x68747541) && |
122 | 10 | (output[2] /*ECX*/ == 0x444D4163) && |
123 | 10 | (output[3] /*EDX*/ == 0x69746E65)) || |
124 | | // Early K5's can return "AMDisbetter!" |
125 | 10 | ((output[1] /*EBX*/ == 0x69444d41) && |
126 | 0 | (output[2] /*ECX*/ == 0x74656273) && |
127 | 0 | (output[3] /*EDX*/ == 0x21726574)); |
128 | 10 | } |
129 | | |
130 | | inline bool IsHygon(const word32 output[4]) |
131 | 0 | { |
132 | | // This is the "HygonGenuine" string. |
133 | 0 | return (output[1] /*EBX*/ == 0x6f677948) && |
134 | 0 | (output[2] /*ECX*/ == 0x656e6975) && |
135 | 0 | (output[3] /*EDX*/ == 0x6e65476e); |
136 | 0 | } |
137 | | |
138 | | inline bool IsVIA(const word32 output[4]) |
139 | 0 | { |
140 | | // This is the "CentaurHauls" string. |
141 | 0 | return ((output[1] /*EBX*/ == 0x746e6543) && |
142 | 0 | (output[2] /*ECX*/ == 0x736c7561) && |
143 | 0 | (output[3] /*EDX*/ == 0x48727561)) || |
144 | | // Some non-PadLock's return "VIA VIA VIA " |
145 | 0 | ((output[1] /*EBX*/ == 0x32414956) && |
146 | 0 | (output[2] /*ECX*/ == 0x32414956) && |
147 | 0 | (output[3] /*EDX*/ == 0x32414956)); |
148 | 0 | } |
149 | | |
150 | | #endif // X86, X32 and X64 |
151 | | |
152 | | #if defined(__APPLE__) |
153 | | |
154 | | // http://stackoverflow.com/questions/45637888/how-to-determine-armv8-features-at-runtime-on-ios |
155 | | class AppleMachineInfo |
156 | | { |
157 | | public: |
158 | | enum { PowerMac=1, Mac, iPhone, iPod, iPad, AppleTV, AppleWatch }; |
159 | | enum { PowerPC=1, I386, I686, X86_64, ARM32, ARMV8, ARMV82, ARMV83 }; |
160 | | |
161 | | AppleMachineInfo() : m_device(0), m_version(0), m_arch(0) |
162 | | { |
163 | | struct utsname systemInfo; |
164 | | systemInfo.machine[0] = '\0'; |
165 | | uname(&systemInfo); |
166 | | |
167 | | std::string machine(systemInfo.machine); |
168 | | |
169 | | std::string::size_type pos = machine.find_first_of("0123456789"); |
170 | | if (pos != std::string::npos) |
171 | | m_version = std::atoi(machine.substr(pos).c_str()); |
172 | | |
173 | | if (machine.find("iPhone") != std::string::npos) |
174 | | { |
175 | | m_device = iPhone; |
176 | | if (m_version >= 6) { m_arch = ARMV8; } |
177 | | else { m_arch = ARM32; } |
178 | | } |
179 | | else if (machine.find("iPod") != std::string::npos) |
180 | | { |
181 | | m_device = iPod; |
182 | | if (m_version >= 6) { m_arch = ARMV8; } |
183 | | else { m_arch = ARM32; } |
184 | | } |
185 | | else if (machine.find("iPad") != std::string::npos) |
186 | | { |
187 | | m_device = iPad; |
188 | | if (m_version >= 5) { m_arch = ARMV8; } |
189 | | else { m_arch = ARM32; } |
190 | | } |
191 | | else if (machine.find("PowerMac") != std::string::npos || |
192 | | machine.find("Power Macintosh") != std::string::npos) |
193 | | { |
194 | | m_device = PowerMac; |
195 | | m_arch = PowerPC; |
196 | | } |
197 | | else if (machine.find("Mac") != std::string::npos || |
198 | | machine.find("Macintosh") != std::string::npos) |
199 | | { |
200 | | #if defined(__x86_64) || defined(__amd64) |
201 | | m_device = Mac; |
202 | | m_arch = X86_64; |
203 | | #elif defined(__i386) |
204 | | m_device = Mac; |
205 | | m_arch = I386; |
206 | | #elif defined(__i686) |
207 | | m_device = Mac; |
208 | | m_arch = I686; |
209 | | #else |
210 | | // Should never get here |
211 | | m_device = Mac; |
212 | | m_arch = 0; |
213 | | #endif |
214 | | } |
215 | | else if (machine.find("AppleTV") != std::string::npos) |
216 | | { |
217 | | m_device = AppleTV; |
218 | | if (m_version >= 4) { m_arch = ARMV8; } |
219 | | else { m_arch = ARM32; } |
220 | | } |
221 | | else if (machine.find("AppleWatch") != std::string::npos) |
222 | | { |
223 | | m_device = AppleWatch; |
224 | | if (m_version >= 4) { m_arch = ARMV8; } |
225 | | else { m_arch = ARM32; } |
226 | | } |
227 | | else if (machine.find("arm64") != std::string::npos) |
228 | | { |
229 | | // M1 machine? |
230 | | std::string brand; |
231 | | size_t size = 32; |
232 | | |
233 | | // Supply an oversized buffer, and avoid |
234 | | // an extra call to sysctlbyname. |
235 | | brand.resize(size); |
236 | | if (sysctlbyname("machdep.cpu.brand_string", &brand[0], &size, NULL, 0) == 0 && size > 0) |
237 | | { |
238 | | if (brand[size-1] == '\0') |
239 | | size--; |
240 | | brand.resize(size); |
241 | | } |
242 | | |
243 | | if (brand == "Apple M1") |
244 | | { |
245 | | m_device = Mac; |
246 | | m_arch = ARMV82; |
247 | | } |
248 | | else |
249 | | { |
250 | | // ??? |
251 | | m_device = 0; |
252 | | m_arch = ARMV8; |
253 | | } |
254 | | } |
255 | | else |
256 | | { |
257 | | CRYPTOPP_ASSERT(0); |
258 | | } |
259 | | } |
260 | | |
261 | | unsigned int Device() const { |
262 | | return m_device; |
263 | | } |
264 | | |
265 | | unsigned int Version() const { |
266 | | return m_version; |
267 | | } |
268 | | |
269 | | unsigned int Arch() const { |
270 | | return m_arch; |
271 | | } |
272 | | |
273 | | bool IsARM32() const { |
274 | | return m_arch == ARM32; |
275 | | } |
276 | | |
277 | | bool IsARMv8() const { |
278 | | return m_arch >= ARMV8; |
279 | | } |
280 | | |
281 | | bool IsARMv82() const { |
282 | | return m_arch >= ARMV82; |
283 | | } |
284 | | |
285 | | bool IsARMv83() const { |
286 | | return m_arch >= ARMV83; |
287 | | } |
288 | | |
289 | | private: |
290 | | unsigned int m_device, m_version, m_arch; |
291 | | }; |
292 | | |
293 | | void GetAppleMachineInfo(unsigned int& device, unsigned int& version, unsigned int& arch) |
294 | | { |
295 | | #if CRYPTOPP_CXX11_STATIC_INIT |
296 | | static const AppleMachineInfo info; |
297 | | #else |
298 | | using CryptoPP::Singleton; |
299 | | const AppleMachineInfo& info = Singleton<AppleMachineInfo>().Ref(); |
300 | | #endif |
301 | | |
302 | | device = info.Device(); |
303 | | version = info.Version(); |
304 | | arch = info.Arch(); |
305 | | } |
306 | | |
307 | | inline bool IsAppleMachineARM32() |
308 | | { |
309 | | static unsigned int arch; |
310 | | if (arch == 0) |
311 | | { |
312 | | unsigned int unused; |
313 | | GetAppleMachineInfo(unused, unused, arch); |
314 | | } |
315 | | return arch == AppleMachineInfo::ARM32; |
316 | | } |
317 | | |
318 | | inline bool IsAppleMachineARMv8() |
319 | | { |
320 | | static unsigned int arch; |
321 | | if (arch == 0) |
322 | | { |
323 | | unsigned int unused; |
324 | | GetAppleMachineInfo(unused, unused, arch); |
325 | | } |
326 | | return arch >= AppleMachineInfo::ARMV8; |
327 | | } |
328 | | |
329 | | inline bool IsAppleMachineARMv82() |
330 | | { |
331 | | static unsigned int arch; |
332 | | if (arch == 0) |
333 | | { |
334 | | unsigned int unused; |
335 | | GetAppleMachineInfo(unused, unused, arch); |
336 | | } |
337 | | return arch >= AppleMachineInfo::ARMV82; |
338 | | } |
339 | | |
340 | | inline bool IsAppleMachineARMv83() |
341 | | { |
342 | | static unsigned int arch; |
343 | | if (arch == 0) |
344 | | { |
345 | | unsigned int unused; |
346 | | GetAppleMachineInfo(unused, unused, arch); |
347 | | } |
348 | | return arch >= AppleMachineInfo::ARMV83; |
349 | | } |
350 | | |
351 | | #endif // __APPLE__ |
352 | | |
353 | | ANONYMOUS_NAMESPACE_END |
354 | | |
355 | | NAMESPACE_BEGIN(CryptoPP) |
356 | | |
357 | | // *************************** IA-32 CPUs *************************** |
358 | | |
359 | | #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) |
360 | | |
361 | | bool CRYPTOPP_SECTION_INIT g_x86DetectionDone = false; |
362 | | bool CRYPTOPP_SECTION_INIT g_hasSSE2 = false; |
363 | | bool CRYPTOPP_SECTION_INIT g_hasSSSE3 = false; |
364 | | bool CRYPTOPP_SECTION_INIT g_hasSSE41 = false; |
365 | | bool CRYPTOPP_SECTION_INIT g_hasSSE42 = false; |
366 | | bool CRYPTOPP_SECTION_INIT g_hasAESNI = false; |
367 | | bool CRYPTOPP_SECTION_INIT g_hasCLMUL = false; |
368 | | bool CRYPTOPP_SECTION_INIT g_hasMOVBE = false; |
369 | | bool CRYPTOPP_SECTION_INIT g_hasAVX = false; |
370 | | bool CRYPTOPP_SECTION_INIT g_hasAVX2 = false; |
371 | | bool CRYPTOPP_SECTION_INIT g_hasADX = false; |
372 | | bool CRYPTOPP_SECTION_INIT g_hasSHA = false; |
373 | | bool CRYPTOPP_SECTION_INIT g_hasRDRAND = false; |
374 | | bool CRYPTOPP_SECTION_INIT g_hasRDSEED = false; |
375 | | bool CRYPTOPP_SECTION_INIT g_isP4 = false; |
376 | | bool CRYPTOPP_SECTION_INIT g_hasPadlockRNG = false; |
377 | | bool CRYPTOPP_SECTION_INIT g_hasPadlockACE = false; |
378 | | bool CRYPTOPP_SECTION_INIT g_hasPadlockACE2 = false; |
379 | | bool CRYPTOPP_SECTION_INIT g_hasPadlockPHE = false; |
380 | | bool CRYPTOPP_SECTION_INIT g_hasPadlockPMM = false; |
381 | | word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; |
382 | | |
383 | | // For Solaris 11 |
384 | | extern bool CPU_ProbeSSE2(); |
385 | | |
386 | | // xcr0 is available when xgetbv is present. |
387 | | // The intrinsic is broke on GCC 8.1 and earlier. Also see |
388 | | // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85684. |
389 | | word64 XGetBV(word32 num) |
390 | 10 | { |
391 | | // Explicitly handle CRYPTOPP_DISABLE_ASM case. |
392 | | // https://github.com/weidai11/cryptopp/issues/1240 |
393 | | #if defined(CRYPTOPP_DISABLE_ASM) |
394 | | return 0; |
395 | | |
396 | | // Required by Visual Studio 2008 and below and Clang on Windows. |
397 | | // Use it for all MSVC-compatible compilers. |
398 | | #elif defined(_M_X64) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) |
399 | | |
400 | | return XGETBV64(num); |
401 | | |
402 | | // Required by Visual Studio 2008 and below and Clang on Windows. |
403 | | // Use it for all MSVC-compatible compilers. |
404 | | #elif defined(_M_IX86) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) |
405 | | |
406 | | word32 a=0, d=0; |
407 | | __asm { |
408 | | push eax |
409 | | push edx |
410 | | push ecx |
411 | | mov ecx, num |
412 | | _emit 0x0f |
413 | | _emit 0x01 |
414 | | _emit 0xd0 |
415 | | mov a, eax |
416 | | mov d, edx |
417 | | pop ecx |
418 | | pop edx |
419 | | pop eax |
420 | | } |
421 | | return (static_cast<word64>(d) << 32) | a; |
422 | | |
423 | | // GCC 4.4 and above |
424 | | #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) |
425 | | |
426 | | word32 a=0, d=0; |
427 | | __asm__ |
428 | | ( |
429 | | "xgetbv" : "=a"(a), "=d"(d) : "c"(num) : "cc" |
430 | | ); |
431 | | return (static_cast<word64>(d) << 32) | a; |
432 | | |
433 | | // Remainder of GCC and compatibles. |
434 | | #elif defined(__GNUC__) || defined(__clang__) || defined(__SUNPRO_CC) |
435 | | |
436 | | // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71659 and |
437 | | // http://www.agner.org/optimize/vectorclass/read.php?i=65 |
438 | 10 | word32 a=0, d=0; |
439 | 10 | __asm__ |
440 | 10 | ( |
441 | 10 | ".byte 0x0f, 0x01, 0xd0" "\n\t" |
442 | 10 | : "=a"(a), "=d"(d) : "c"(num) : "cc" |
443 | 10 | ); |
444 | 10 | return (static_cast<word64>(d) << 32) | a; |
445 | | #else |
446 | | # error "Need an xgetbv function" |
447 | | #endif |
448 | 10 | } |
449 | | |
450 | | // No inline due to Borland/Embarcadero and Issue 498 |
451 | | // cpu.cpp (131): E2211 Inline assembly not allowed in inline and template functions |
452 | | bool CpuId(word32 func, word32 subfunc, word32 output[4]) |
453 | 40 | { |
454 | | // Explicitly handle CRYPTOPP_DISABLE_ASM case. |
455 | | // https://github.com/weidai11/cryptopp/issues/1240 |
456 | | #if defined(CRYPTOPP_DISABLE_ASM) |
457 | | output[0] = output[1] = output[2] = output[3] = 0; |
458 | | return false; |
459 | | |
460 | | // Required by Visual Studio 2008 and below and Clang on Windows. |
461 | | // Use it for all MSVC-compatible compilers. |
462 | | #elif defined(_M_X64) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) |
463 | | |
464 | | CPUID64(func, subfunc, output); |
465 | | return true; |
466 | | |
467 | | // Required by Visual Studio 2008 and below and Clang on Windows. |
468 | | // Use it for all MSVC-compatible compilers. |
469 | | #elif defined(_M_IX86) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) |
470 | | |
471 | | __try |
472 | | { |
473 | | // Borland/Embarcadero and Issue 500 |
474 | | // Local variables for cpuid output |
475 | | word32 a, b, c, d; |
476 | | __asm |
477 | | { |
478 | | push ebx |
479 | | mov eax, func |
480 | | mov ecx, subfunc |
481 | | cpuid |
482 | | mov [a], eax |
483 | | mov [b], ebx |
484 | | mov [c], ecx |
485 | | mov [d], edx |
486 | | pop ebx |
487 | | } |
488 | | output[0] = a; |
489 | | output[1] = b; |
490 | | output[2] = c; |
491 | | output[3] = d; |
492 | | } |
493 | | __except (EXCEPTION_EXECUTE_HANDLER) |
494 | | { |
495 | | return false; |
496 | | } |
497 | | |
498 | | return true; |
499 | | |
500 | | // Linux, Unix, OS X, Solaris, Cygwin, MinGW |
501 | | #else |
502 | | |
503 | | // longjmp and clobber warnings. Volatile is required. |
504 | | // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 |
505 | 40 | volatile bool result = true; |
506 | | |
507 | 40 | volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); |
508 | 40 | if (oldHandler == SIG_ERR) |
509 | 0 | return false; |
510 | | |
511 | 40 | # ifndef __MINGW32__ |
512 | 40 | volatile sigset_t oldMask; |
513 | 40 | if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask) != 0) |
514 | 0 | { |
515 | 0 | signal(SIGILL, oldHandler); |
516 | 0 | return false; |
517 | 0 | } |
518 | 40 | # endif |
519 | | |
520 | 40 | if (setjmp(s_jmpNoCPUID)) |
521 | 0 | result = false; |
522 | 40 | else |
523 | 40 | { |
524 | 40 | asm volatile |
525 | 40 | ( |
526 | | // save ebx in case -fPIC is being used |
527 | 40 | # if CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 |
528 | 40 | "pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx" |
529 | | # else |
530 | | "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx" |
531 | | # endif |
532 | 40 | : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3]) |
533 | 40 | : "a" (func), "c" (subfunc) |
534 | 40 | : "cc" |
535 | 40 | ); |
536 | 40 | } |
537 | | |
538 | 40 | # ifndef __MINGW32__ |
539 | 40 | sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); |
540 | 40 | # endif |
541 | | |
542 | 40 | signal(SIGILL, oldHandler); |
543 | 40 | return result; |
544 | 40 | #endif |
545 | 40 | } |
546 | | |
547 | | void DetectX86Features() |
548 | 10 | { |
549 | | // Coverity finding CID 171239. Initialize arrays. |
550 | | // Indexes: EAX=0, EBX=1, ECX=2, EDX=3 |
551 | 10 | word32 cpuid0[4]={0}, cpuid1[4]={0}, cpuid2[4]={0}; |
552 | | |
553 | | #if defined(CRYPTOPP_DISABLE_ASM) |
554 | | // Not available |
555 | | goto done; |
556 | | #else |
557 | 10 | if (!CpuId(0, 0, cpuid0)) |
558 | 0 | goto done; |
559 | 10 | if (!CpuId(1, 0, cpuid1)) |
560 | 0 | goto done; |
561 | 10 | #endif |
562 | | |
563 | 10 | CRYPTOPP_CONSTANT(EAX_REG = 0); |
564 | 10 | CRYPTOPP_CONSTANT(EBX_REG = 1); |
565 | 10 | CRYPTOPP_CONSTANT(ECX_REG = 2); |
566 | 10 | CRYPTOPP_CONSTANT(EDX_REG = 3); |
567 | | |
568 | 10 | CRYPTOPP_CONSTANT(MMX_FLAG = (1 << 24)); // EDX |
569 | 10 | CRYPTOPP_CONSTANT(SSE_FLAG = (1 << 25)); // EDX |
570 | 10 | CRYPTOPP_CONSTANT(SSE2_FLAG = (1 << 26)); // EDX |
571 | | |
572 | 10 | CRYPTOPP_CONSTANT(SSE3_FLAG = (1 << 0)); // ECX |
573 | 10 | CRYPTOPP_CONSTANT(SSSE3_FLAG = (1 << 9)); // ECX |
574 | 10 | CRYPTOPP_CONSTANT(SSE41_FLAG = (1 << 19)); // ECX |
575 | 10 | CRYPTOPP_CONSTANT(SSE42_FLAG = (1 << 20)); // ECX |
576 | 10 | CRYPTOPP_CONSTANT(MOVBE_FLAG = (1 << 22)); // ECX |
577 | 10 | CRYPTOPP_CONSTANT(AESNI_FLAG = (1 << 25)); // ECX |
578 | 10 | CRYPTOPP_CONSTANT(CLMUL_FLAG = (1 << 1)); // ECX |
579 | | |
580 | 10 | CRYPTOPP_CONSTANT(XSAVE_FLAG = (1 << 26)); // ECX |
581 | 10 | CRYPTOPP_CONSTANT(OSXSAVE_FLAG = (1 << 27)); // ECX |
582 | | |
583 | 10 | CRYPTOPP_CONSTANT(AVX_FLAG = (3 << 27)); // ECX |
584 | 10 | CRYPTOPP_CONSTANT(YMM_FLAG = (3 << 1)); // CR0 |
585 | | |
586 | | // x86_64 machines don't check some flags because SSE2 |
587 | | // is part of the core instruction set architecture |
588 | 10 | CRYPTOPP_UNUSED(MMX_FLAG); CRYPTOPP_UNUSED(SSE_FLAG); |
589 | 10 | CRYPTOPP_UNUSED(SSE2_FLAG); CRYPTOPP_UNUSED(SSE3_FLAG); |
590 | 10 | CRYPTOPP_UNUSED(XSAVE_FLAG); |
591 | | |
592 | 10 | #if (CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) |
593 | | // 64-bit core instruction set includes SSE2. Just check |
594 | | // the OS enabled SSE2 support using OSXSAVE. |
595 | 10 | g_hasSSE2 = (cpuid1[ECX_REG] & OSXSAVE_FLAG) != 0; |
596 | | #else |
597 | | // Check the processor supports SSE2. Then use OSXSAVE to |
598 | | // signal OS support for SSE2 to avoid probes. |
599 | | // Also see http://stackoverflow.com/a/22521619/608639 |
600 | | // and http://github.com/weidai11/cryptopp/issues/511. |
601 | | if ((cpuid1[EDX_REG] & SSE2_FLAG) == SSE2_FLAG) |
602 | | g_hasSSE2 = (cpuid1[ECX_REG] & XSAVE_FLAG) != 0 && |
603 | | (cpuid1[ECX_REG] & OSXSAVE_FLAG) != 0; |
604 | | #endif |
605 | | |
606 | | // Solaris 11 i86pc does not signal SSE support using |
607 | | // OSXSAVE. Additionally, Fedora 38 on a 2015 Celeron |
608 | | // N3700 does not set OSXSAVE. So we need to explicitly |
609 | | // probe for SSE support on rare occasions. Ugh... |
610 | 10 | if (g_hasSSE2 == false) |
611 | 0 | { |
612 | 0 | g_hasSSE2 = CPU_ProbeSSE2(); |
613 | 0 | if (g_hasSSE2 == false) |
614 | 0 | goto done; |
615 | 0 | } |
616 | | |
617 | 10 | g_hasSSSE3 = (cpuid1[ECX_REG] & SSSE3_FLAG) != 0; |
618 | 10 | g_hasSSE41 = (cpuid1[ECX_REG] & SSE41_FLAG) != 0; |
619 | 10 | g_hasSSE42 = (cpuid1[ECX_REG] & SSE42_FLAG) != 0; |
620 | 10 | g_hasMOVBE = (cpuid1[ECX_REG] & MOVBE_FLAG) != 0; |
621 | 10 | g_hasAESNI = (cpuid1[ECX_REG] & AESNI_FLAG) != 0; |
622 | 10 | g_hasCLMUL = (cpuid1[ECX_REG] & CLMUL_FLAG) != 0; |
623 | | |
624 | | // AVX is similar to SSE. Check if AVX is available on the cpu, then |
625 | | // check if the OS enabled XSAVE/XRESTORE for the extended registers. |
626 | | // https://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled |
627 | 10 | if ((cpuid1[ECX_REG] & AVX_FLAG) == AVX_FLAG) |
628 | 10 | { |
629 | 10 | word64 xcr0 = XGetBV(0); |
630 | 10 | g_hasAVX = (xcr0 & YMM_FLAG) == YMM_FLAG; |
631 | 10 | } |
632 | | |
633 | 10 | if (IsIntel(cpuid0)) |
634 | 0 | { |
635 | 0 | CRYPTOPP_CONSTANT(RDRAND_FLAG = (1 << 30)); |
636 | 0 | CRYPTOPP_CONSTANT(RDSEED_FLAG = (1 << 18)); |
637 | 0 | CRYPTOPP_CONSTANT( ADX_FLAG = (1 << 19)); |
638 | 0 | CRYPTOPP_CONSTANT( SHA_FLAG = (1 << 29)); |
639 | 0 | CRYPTOPP_CONSTANT( AVX2_FLAG = (1 << 5)); |
640 | |
|
641 | 0 | g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf; |
642 | 0 | g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1); |
643 | 0 | g_hasRDRAND = (cpuid1[ECX_REG] & RDRAND_FLAG) != 0; |
644 | |
|
645 | 0 | if (cpuid0[EAX_REG] >= 7) |
646 | 0 | { |
647 | 0 | if (CpuId(7, 0, cpuid2)) |
648 | 0 | { |
649 | 0 | g_hasRDSEED = (cpuid2[EBX_REG] & RDSEED_FLAG) != 0; |
650 | 0 | g_hasADX = (cpuid2[EBX_REG] & ADX_FLAG) != 0; |
651 | 0 | g_hasSHA = (cpuid2[EBX_REG] & SHA_FLAG) != 0; |
652 | 0 | g_hasAVX2 = (cpuid2[EBX_REG] & AVX2_FLAG) != 0; |
653 | 0 | } |
654 | 0 | } |
655 | 0 | } |
656 | 10 | else if (IsAMD(cpuid0) || IsHygon(cpuid0)) |
657 | 10 | { |
658 | 10 | CRYPTOPP_CONSTANT(RDRAND_FLAG = (1 << 30)); |
659 | 10 | CRYPTOPP_CONSTANT(RDSEED_FLAG = (1 << 18)); |
660 | 10 | CRYPTOPP_CONSTANT( ADX_FLAG = (1 << 19)); |
661 | 10 | CRYPTOPP_CONSTANT( SHA_FLAG = (1 << 29)); |
662 | 10 | CRYPTOPP_CONSTANT( AVX2_FLAG = (1 << 5)); |
663 | | |
664 | 10 | CpuId(0x80000005, 0, cpuid2); |
665 | 10 | g_cacheLineSize = GETBYTE(cpuid2[ECX_REG], 0); |
666 | 10 | g_hasRDRAND = (cpuid1[ECX_REG] & RDRAND_FLAG) != 0; |
667 | | |
668 | 10 | if (cpuid0[EAX_REG] >= 7) |
669 | 10 | { |
670 | 10 | if (CpuId(7, 0, cpuid2)) |
671 | 10 | { |
672 | 10 | g_hasRDSEED = (cpuid2[EBX_REG] & RDSEED_FLAG) != 0; |
673 | 10 | g_hasADX = (cpuid2[EBX_REG] & ADX_FLAG) != 0; |
674 | 10 | g_hasSHA = (cpuid2[EBX_REG] & SHA_FLAG) != 0; |
675 | 10 | g_hasAVX2 = (cpuid2[EBX_REG] & AVX2_FLAG) != 0; |
676 | 10 | } |
677 | 10 | } |
678 | | |
679 | | // Unconditionally disable RDRAND and RDSEED on AMD cpu's with family 15h or 16h. |
680 | | // See Crypto++ Issue 924, https://github.com/weidai11/cryptopp/issues/924, |
681 | | // Clear RDRAND CPUID bit on AMD family 15h/16h, https://lore.kernel.org/patchwork/patch/1115413/, |
682 | | // and AMD CPUID Specification, https://www.amd.com/system/files/TechDocs/25481.pdf |
683 | 10 | { |
684 | 10 | CRYPTOPP_CONSTANT(FAMILY_BASE_FLAG = (0x0f << 8)); |
685 | 10 | CRYPTOPP_CONSTANT(FAMILY_EXT_FLAG = (0xff << 20)); |
686 | | |
687 | 10 | word32 family = (cpuid1[0] & FAMILY_BASE_FLAG) >> 8; |
688 | 10 | if (family == 0xf) |
689 | 10 | family += (cpuid1[0] & FAMILY_EXT_FLAG) >> 20; |
690 | 10 | if (family == 0x15 || family == 0x16) |
691 | 0 | { |
692 | 0 | g_hasRDRAND = false; |
693 | 0 | g_hasRDSEED = false; |
694 | 0 | } |
695 | 10 | } |
696 | 10 | } |
697 | 0 | else if (IsVIA(cpuid0)) |
698 | 0 | { |
699 | | // Two bits: available and enabled |
700 | 0 | CRYPTOPP_CONSTANT( RNG_FLAGS = (0x3 << 2)); |
701 | 0 | CRYPTOPP_CONSTANT( ACE_FLAGS = (0x3 << 6)); |
702 | 0 | CRYPTOPP_CONSTANT(ACE2_FLAGS = (0x3 << 8)); |
703 | 0 | CRYPTOPP_CONSTANT( PHE_FLAGS = (0x3 << 10)); |
704 | 0 | CRYPTOPP_CONSTANT( PMM_FLAGS = (0x3 << 12)); |
705 | |
|
706 | 0 | CpuId(0xC0000000, 0, cpuid2); |
707 | 0 | word32 extendedFeatures = cpuid2[0]; |
708 | |
|
709 | 0 | if (extendedFeatures >= 0xC0000001) |
710 | 0 | { |
711 | 0 | CpuId(0xC0000001, 0, cpuid2); |
712 | 0 | g_hasPadlockRNG = (cpuid2[EDX_REG] & RNG_FLAGS) != 0; |
713 | 0 | g_hasPadlockACE = (cpuid2[EDX_REG] & ACE_FLAGS) != 0; |
714 | 0 | g_hasPadlockACE2 = (cpuid2[EDX_REG] & ACE2_FLAGS) != 0; |
715 | 0 | g_hasPadlockPHE = (cpuid2[EDX_REG] & PHE_FLAGS) != 0; |
716 | 0 | g_hasPadlockPMM = (cpuid2[EDX_REG] & PMM_FLAGS) != 0; |
717 | 0 | } |
718 | |
|
719 | 0 | if (extendedFeatures >= 0xC0000005) |
720 | 0 | { |
721 | 0 | CpuId(0xC0000005, 0, cpuid2); |
722 | 0 | g_cacheLineSize = GETBYTE(cpuid2[ECX_REG], 0); |
723 | 0 | } |
724 | 0 | } |
725 | | |
726 | | // Keep AVX2 in sync with OS support for AVX. AVX tests both |
727 | | // cpu support and OS support, while AVX2 only tests cpu support. |
728 | 10 | g_hasAVX2 &= g_hasAVX; |
729 | | |
730 | 10 | done: |
731 | | |
732 | 10 | #if defined(_SC_LEVEL1_DCACHE_LINESIZE) |
733 | | // Glibc does not implement on some platforms. The runtime returns 0 instead of error. |
734 | | // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/sysconf.c |
735 | 10 | int cacheLineSize = (int)sysconf(_SC_LEVEL1_DCACHE_LINESIZE); |
736 | 10 | if (g_cacheLineSize == 0 && cacheLineSize > 0) |
737 | 0 | g_cacheLineSize = cacheLineSize; |
738 | 10 | #endif |
739 | | |
740 | 10 | if (g_cacheLineSize == 0) |
741 | 0 | g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; |
742 | | |
743 | 10 | *const_cast<volatile bool*>(&g_x86DetectionDone) = true; |
744 | 10 | } |
745 | | |
746 | | // *************************** ARM-32, Aarch32 and Aarch64 *************************** |
747 | | |
748 | | #elif (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8) |
749 | | |
750 | | bool CRYPTOPP_SECTION_INIT g_ArmDetectionDone = false; |
751 | | bool CRYPTOPP_SECTION_INIT g_hasARMv7 = false; |
752 | | bool CRYPTOPP_SECTION_INIT g_hasNEON = false; |
753 | | bool CRYPTOPP_SECTION_INIT g_hasPMULL = false; |
754 | | bool CRYPTOPP_SECTION_INIT g_hasCRC32 = false; |
755 | | bool CRYPTOPP_SECTION_INIT g_hasAES = false; |
756 | | bool CRYPTOPP_SECTION_INIT g_hasSHA1 = false; |
757 | | bool CRYPTOPP_SECTION_INIT g_hasSHA2 = false; |
758 | | bool CRYPTOPP_SECTION_INIT g_hasSHA512 = false; |
759 | | bool CRYPTOPP_SECTION_INIT g_hasSHA3 = false; |
760 | | bool CRYPTOPP_SECTION_INIT g_hasSM3 = false; |
761 | | bool CRYPTOPP_SECTION_INIT g_hasSM4 = false; |
762 | | word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; |
763 | | |
764 | | // ARM does not have an unprivileged equivalent to CPUID on IA-32. We have to |
765 | | // jump through some hoops to detect features on a wide array of platforms. |
766 | | // Our strategy is two part. First, attempt to *Query* the OS for a feature, |
767 | | // like using getauxval on Linux. If that fails, then *Probe* the cpu |
768 | | // executing an instruction and an observe a SIGILL if unsupported. The probes |
769 | | // are in source files where compilation options like -march=armv8-a+crc make |
770 | | // intrinsics available. They are expensive when compared to a standard OS |
771 | | // feature query. Always perform the feature query first. For Linux see |
772 | | // http://sourceware.org/ml/libc-help/2017-08/msg00012.html |
773 | | // Avoid probes on Apple platforms because Apple's signal handling for SIGILLs |
774 | | // appears broken. We are trying to figure out a way to feature test without |
775 | | // probes. Also see http://stackoverflow.com/a/11197770/608639 and |
776 | | // http://gist.github.com/erkanyildiz/390a480f27e86f8cd6ba. |
777 | | |
778 | | extern bool CPU_ProbeARMv7(); |
779 | | extern bool CPU_ProbeNEON(); |
780 | | extern bool CPU_ProbeCRC32(); |
781 | | extern bool CPU_ProbeAES(); |
782 | | extern bool CPU_ProbeSHA1(); |
783 | | extern bool CPU_ProbeSHA256(); |
784 | | extern bool CPU_ProbeSHA512(); |
785 | | extern bool CPU_ProbeSHA3(); |
786 | | extern bool CPU_ProbeSM3(); |
787 | | extern bool CPU_ProbeSM4(); |
788 | | extern bool CPU_ProbePMULL(); |
789 | | |
790 | | // https://github.com/torvalds/linux/blob/master/arch/arm/include/uapi/asm/hwcap.h |
791 | | // https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h |
792 | | #ifndef HWCAP_ARMv7 |
793 | | # define HWCAP_ARMv7 (1 << 29) |
794 | | #endif |
795 | | #ifndef HWCAP_ASIMD |
796 | | # define HWCAP_ASIMD (1 << 1) |
797 | | #endif |
798 | | #ifndef HWCAP_NEON |
799 | | # define HWCAP_NEON (1 << 12) |
800 | | #endif |
801 | | #ifndef HWCAP_CRC32 |
802 | | # define HWCAP_CRC32 (1 << 7) |
803 | | #endif |
804 | | #ifndef HWCAP2_CRC32 |
805 | | # define HWCAP2_CRC32 (1 << 4) |
806 | | #endif |
807 | | #ifndef HWCAP_PMULL |
808 | | # define HWCAP_PMULL (1 << 4) |
809 | | #endif |
810 | | #ifndef HWCAP2_PMULL |
811 | | # define HWCAP2_PMULL (1 << 1) |
812 | | #endif |
813 | | #ifndef HWCAP_AES |
814 | | # define HWCAP_AES (1 << 3) |
815 | | #endif |
816 | | #ifndef HWCAP2_AES |
817 | | # define HWCAP2_AES (1 << 0) |
818 | | #endif |
819 | | #ifndef HWCAP_SHA1 |
820 | | # define HWCAP_SHA1 (1 << 5) |
821 | | #endif |
822 | | #ifndef HWCAP_SHA2 |
823 | | # define HWCAP_SHA2 (1 << 6) |
824 | | #endif |
825 | | #ifndef HWCAP2_SHA1 |
826 | | # define HWCAP2_SHA1 (1 << 2) |
827 | | #endif |
828 | | #ifndef HWCAP2_SHA2 |
829 | | # define HWCAP2_SHA2 (1 << 3) |
830 | | #endif |
831 | | #ifndef HWCAP_SHA3 |
832 | | # define HWCAP_SHA3 (1 << 17) |
833 | | #endif |
834 | | #ifndef HWCAP_SM3 |
835 | | # define HWCAP_SM3 (1 << 18) |
836 | | #endif |
837 | | #ifndef HWCAP_SM4 |
838 | | # define HWCAP_SM4 (1 << 19) |
839 | | #endif |
840 | | #ifndef HWCAP_SHA512 |
841 | | # define HWCAP_SHA512 (1 << 21) |
842 | | #endif |
843 | | |
844 | | inline bool CPU_QueryARMv7() |
845 | | { |
846 | | #if defined(__ANDROID__) && defined(__arm__) |
847 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && |
848 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_ARMv7) != 0)) |
849 | | return true; |
850 | | #elif defined(__linux__) && defined(__arm__) |
851 | | if ((getauxval(AT_HWCAP) & HWCAP_ARMv7) != 0 || |
852 | | (getauxval(AT_HWCAP) & HWCAP_NEON) != 0) |
853 | | return true; |
854 | | #elif defined(__APPLE__) && defined(__arm__) |
855 | | // Apple hardware is ARMv7 or above. |
856 | | return true; |
857 | | #elif defined(_WIN32) && defined(_M_ARM64) |
858 | | // Windows 10 ARM64 is only supported on Armv8a and above |
859 | | return true; |
860 | | #endif |
861 | | return false; |
862 | | } |
863 | | |
864 | | inline bool CPU_QueryNEON() |
865 | | { |
866 | | #if defined(__ANDROID__) && defined(__aarch64__) |
867 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && |
868 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_ASIMD) != 0)) |
869 | | return true; |
870 | | #elif defined(__ANDROID__) && defined(__arm__) |
871 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && |
872 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0)) |
873 | | return true; |
874 | | #elif defined(__linux__) && defined(__aarch64__) |
875 | | if ((getauxval(AT_HWCAP) & HWCAP_ASIMD) != 0) |
876 | | return true; |
877 | | #elif defined(__linux__) && defined(__aarch32__) |
878 | | if ((getauxval(AT_HWCAP2) & HWCAP2_ASIMD) != 0) |
879 | | return true; |
880 | | #elif defined(__linux__) && defined(__arm__) |
881 | | if ((getauxval(AT_HWCAP) & HWCAP_NEON) != 0) |
882 | | return true; |
883 | | #elif defined(__APPLE__) && defined(__aarch64__) |
884 | | // Core feature set for Aarch32 and Aarch64. |
885 | | if (IsAppleMachineARMv8()) |
886 | | return true; |
887 | | #elif defined(_WIN32) && defined(_M_ARM64) |
888 | | // Windows 10 ARM64 is only supported on Armv8a and above |
889 | | if (IsProcessorFeaturePresent(PF_ARM_V8_INSTRUCTIONS_AVAILABLE) != 0) |
890 | | return true; |
891 | | #endif |
892 | | return false; |
893 | | } |
894 | | |
895 | | inline bool CPU_QueryCRC32() |
896 | | { |
897 | | #if defined(__ANDROID__) && defined(__aarch64__) |
898 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && |
899 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_CRC32) != 0)) |
900 | | return true; |
901 | | #elif defined(__ANDROID__) && defined(__aarch32__) |
902 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && |
903 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_CRC32) != 0)) |
904 | | return true; |
905 | | #elif defined(__linux__) && defined(__aarch64__) |
906 | | if ((getauxval(AT_HWCAP) & HWCAP_CRC32) != 0) |
907 | | return true; |
908 | | #elif defined(__linux__) && defined(__aarch32__) |
909 | | if ((getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0) |
910 | | return true; |
911 | | #elif defined(__APPLE__) && defined(__aarch64__) |
912 | | // M1 processor |
913 | | if (IsAppleMachineARMv82()) |
914 | | return true; |
915 | | #elif defined(_WIN32) && defined(_M_ARM64) |
916 | | if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != 0) |
917 | | return true; |
918 | | #endif |
919 | | return false; |
920 | | } |
921 | | |
922 | | inline bool CPU_QueryPMULL() |
923 | | { |
924 | | #if defined(__ANDROID__) && defined(__aarch64__) |
925 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && |
926 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_PMULL) != 0)) |
927 | | return true; |
928 | | #elif defined(__ANDROID__) && defined(__aarch32__) |
929 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && |
930 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_PMULL) != 0)) |
931 | | return true; |
932 | | #elif defined(__linux__) && defined(__aarch64__) |
933 | | if ((getauxval(AT_HWCAP) & HWCAP_PMULL) != 0) |
934 | | return true; |
935 | | #elif defined(__linux__) && defined(__aarch32__) |
936 | | if ((getauxval(AT_HWCAP2) & HWCAP2_PMULL) != 0) |
937 | | return true; |
938 | | #elif defined(__APPLE__) && defined(__aarch64__) |
939 | | // M1 processor |
940 | | if (IsAppleMachineARMv82()) |
941 | | return true; |
942 | | #elif defined(_WIN32) && defined(_M_ARM64) |
943 | | if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0) |
944 | | return true; |
945 | | #endif |
946 | | return false; |
947 | | } |
948 | | |
949 | | inline bool CPU_QueryAES() |
950 | | { |
951 | | #if defined(__ANDROID__) && defined(__aarch64__) |
952 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && |
953 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_AES) != 0)) |
954 | | return true; |
955 | | #elif defined(__ANDROID__) && defined(__aarch32__) |
956 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && |
957 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_AES) != 0)) |
958 | | return true; |
959 | | #elif defined(__linux__) && defined(__aarch64__) |
960 | | if ((getauxval(AT_HWCAP) & HWCAP_AES) != 0) |
961 | | return true; |
962 | | #elif defined(__linux__) && defined(__aarch32__) |
963 | | if ((getauxval(AT_HWCAP2) & HWCAP2_AES) != 0) |
964 | | return true; |
965 | | #elif defined(__APPLE__) && defined(__aarch64__) |
966 | | // M1 processor |
967 | | if (IsAppleMachineARMv82()) |
968 | | return true; |
969 | | #elif defined(_WIN32) && defined(_M_ARM64) |
970 | | if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0) |
971 | | return true; |
972 | | #endif |
973 | | return false; |
974 | | } |
975 | | |
976 | | inline bool CPU_QuerySHA1() |
977 | | { |
978 | | #if defined(__ANDROID__) && defined(__aarch64__) |
979 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && |
980 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA1) != 0)) |
981 | | return true; |
982 | | #elif defined(__ANDROID__) && defined(__aarch32__) |
983 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && |
984 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA1) != 0)) |
985 | | return true; |
986 | | #elif defined(__linux__) && defined(__aarch64__) |
987 | | if ((getauxval(AT_HWCAP) & HWCAP_SHA1) != 0) |
988 | | return true; |
989 | | #elif defined(__linux__) && defined(__aarch32__) |
990 | | if ((getauxval(AT_HWCAP2) & HWCAP2_SHA1) != 0) |
991 | | return true; |
992 | | #elif defined(__APPLE__) && defined(__aarch64__) |
993 | | // M1 processor |
994 | | if (IsAppleMachineARMv82()) |
995 | | return true; |
996 | | #elif defined(_WIN32) && defined(_M_ARM64) |
997 | | if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0) |
998 | | return true; |
999 | | #endif |
1000 | | return false; |
1001 | | } |
1002 | | |
1003 | | inline bool CPU_QuerySHA256() |
1004 | | { |
1005 | | #if defined(__ANDROID__) && defined(__aarch64__) |
1006 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && |
1007 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA2) != 0)) |
1008 | | return true; |
1009 | | #elif defined(__ANDROID__) && defined(__aarch32__) |
1010 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && |
1011 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA2) != 0)) |
1012 | | return true; |
1013 | | #elif defined(__linux__) && defined(__aarch64__) |
1014 | | if ((getauxval(AT_HWCAP) & HWCAP_SHA2) != 0) |
1015 | | return true; |
1016 | | #elif defined(__linux__) && defined(__aarch32__) |
1017 | | if ((getauxval(AT_HWCAP2) & HWCAP2_SHA2) != 0) |
1018 | | return true; |
1019 | | #elif defined(__APPLE__) && defined(__aarch64__) |
1020 | | // M1 processor |
1021 | | if (IsAppleMachineARMv82()) |
1022 | | return true; |
1023 | | #elif defined(_WIN32) && defined(_M_ARM64) |
1024 | | if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0) |
1025 | | return true; |
1026 | | #endif |
1027 | | return false; |
1028 | | } |
1029 | | |
1030 | | // Some ARMv8.2 features are disabled at the moment |
1031 | | inline bool CPU_QuerySHA3() |
1032 | | { |
1033 | | // According to the ARM manual, SHA3 depends upon SHA1 and SHA2. |
1034 | | // If SHA1 and SHA2 are not present, then SHA3 and SHA512 are |
1035 | | // not present. Also see Arm A64 Instruction Set Architecture, |
1036 | | // https://developer.arm.com/documentation/ddi0596/2020-12/ |
1037 | | if (!g_hasSHA1 || !g_hasSHA2) { return false; } |
1038 | | |
1039 | | #if defined(__ANDROID__) && defined(__aarch64__) && 0 |
1040 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && |
1041 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA3) != 0)) |
1042 | | return true; |
1043 | | #elif defined(__ANDROID__) && defined(__aarch32__) && 0 |
1044 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && |
1045 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA3) != 0)) |
1046 | | return true; |
1047 | | #elif defined(__linux__) && defined(__aarch64__) |
1048 | | if ((getauxval(AT_HWCAP) & HWCAP_SHA3) != 0) |
1049 | | return true; |
1050 | | #elif defined(__linux__) && defined(__aarch32__) |
1051 | | if ((getauxval(AT_HWCAP2) & HWCAP2_SHA3) != 0) |
1052 | | return true; |
1053 | | #elif defined(__APPLE__) && defined(__aarch64__) |
1054 | | // M1 processor |
1055 | | if (IsAppleMachineARMv82()) |
1056 | | return true; |
1057 | | #endif |
1058 | | return false; |
1059 | | } |
1060 | | |
1061 | | // Some ARMv8.2 features are disabled at the moment |
1062 | | inline bool CPU_QuerySHA512() |
1063 | | { |
1064 | | // According to the ARM manual, SHA512 depends upon SHA1 and SHA2. |
1065 | | // If SHA1 and SHA2 are not present, then SHA3 and SHA512 are |
1066 | | // not present. Also see Arm A64 Instruction Set Architecture, |
1067 | | // https://developer.arm.com/documentation/ddi0596/2020-12/ |
1068 | | if (!g_hasSHA1 || !g_hasSHA2) { return false; } |
1069 | | |
1070 | | #if defined(__ANDROID__) && defined(__aarch64__) && 0 |
1071 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && |
1072 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA512) != 0)) |
1073 | | return true; |
1074 | | #elif defined(__ANDROID__) && defined(__aarch32__) && 0 |
1075 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && |
1076 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA512) != 0)) |
1077 | | return true; |
1078 | | #elif defined(__linux__) && defined(__aarch64__) |
1079 | | if ((getauxval(AT_HWCAP) & HWCAP_SHA512) != 0) |
1080 | | return true; |
1081 | | #elif defined(__linux__) && defined(__aarch32__) |
1082 | | if ((getauxval(AT_HWCAP2) & HWCAP2_SHA512) != 0) |
1083 | | return true; |
1084 | | #elif defined(__APPLE__) && defined(__aarch64__) |
1085 | | // M1 processor |
1086 | | if (IsAppleMachineARMv82()) |
1087 | | return true; |
1088 | | #endif |
1089 | | return false; |
1090 | | } |
1091 | | |
1092 | | // Some ARMv8.2 features are disabled at the moment |
1093 | | inline bool CPU_QuerySM3() |
1094 | | { |
1095 | | #if defined(__ANDROID__) && defined(__aarch64__) && 0 |
1096 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && |
1097 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SM3) != 0)) |
1098 | | return true; |
1099 | | #elif defined(__ANDROID__) && defined(__aarch32__) && 0 |
1100 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && |
1101 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SM3) != 0)) |
1102 | | return true; |
1103 | | #elif defined(__linux__) && defined(__aarch64__) |
1104 | | if ((getauxval(AT_HWCAP) & HWCAP_SM3) != 0) |
1105 | | return true; |
1106 | | #elif defined(__linux__) && defined(__aarch32__) |
1107 | | if ((getauxval(AT_HWCAP2) & HWCAP2_SM3) != 0) |
1108 | | return true; |
1109 | | #elif defined(__APPLE__) && defined(__aarch64__) && 0 |
1110 | | // No Apple support yet. |
1111 | | #endif |
1112 | | return false; |
1113 | | } |
1114 | | |
1115 | | // Some ARMv8.2 features are disabled at the moment |
1116 | | inline bool CPU_QuerySM4() |
1117 | | { |
1118 | | #if defined(__ANDROID__) && defined(__aarch64__) && 0 |
1119 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && |
1120 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SM4) != 0)) |
1121 | | return true; |
1122 | | #elif defined(__ANDROID__) && defined(__aarch32__) && 0 |
1123 | | if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && |
1124 | | ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SM4) != 0)) |
1125 | | return true; |
1126 | | #elif defined(__linux__) && defined(__aarch64__) |
1127 | | if ((getauxval(AT_HWCAP) & HWCAP_SM4) != 0) |
1128 | | return true; |
1129 | | #elif defined(__linux__) && defined(__aarch32__) |
1130 | | if ((getauxval(AT_HWCAP2) & HWCAP2_SM4) != 0) |
1131 | | return true; |
1132 | | #elif defined(__APPLE__) && defined(__aarch64__) && 0 |
1133 | | // No Apple support yet. |
1134 | | #endif |
1135 | | return false; |
1136 | | } |
1137 | | |
1138 | | void DetectArmFeatures() |
1139 | | { |
1140 | | #ifndef CRYPTOPP_DISABLE_ASM |
1141 | | |
1142 | | // The CPU_ProbeXXX's return false for OSes which |
1143 | | // can't tolerate SIGILL-based probes |
1144 | | g_hasARMv7 = CPU_QueryARMv7() || CPU_ProbeARMv7(); |
1145 | | g_hasNEON = CPU_QueryNEON() || CPU_ProbeNEON(); |
1146 | | g_hasCRC32 = CPU_QueryCRC32() || CPU_ProbeCRC32(); |
1147 | | g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL(); |
1148 | | g_hasAES = CPU_QueryAES() || CPU_ProbeAES(); |
1149 | | g_hasSHA1 = CPU_QuerySHA1() || CPU_ProbeSHA1(); |
1150 | | g_hasSHA2 = CPU_QuerySHA256() || CPU_ProbeSHA256(); |
1151 | | g_hasSHA512 = CPU_QuerySHA512(); // || CPU_ProbeSHA512(); |
1152 | | g_hasSHA3 = CPU_QuerySHA3(); // || CPU_ProbeSHA3(); |
1153 | | g_hasSM3 = CPU_QuerySM3(); // || CPU_ProbeSM3(); |
1154 | | g_hasSM4 = CPU_QuerySM4(); // || CPU_ProbeSM4(); |
1155 | | |
1156 | | #if defined(_SC_LEVEL1_DCACHE_LINESIZE) |
1157 | | // Glibc does not implement on some platforms. The runtime returns 0 instead of error. |
1158 | | // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/sysconf.c |
1159 | | int cacheLineSize = (int)sysconf(_SC_LEVEL1_DCACHE_LINESIZE); |
1160 | | if (cacheLineSize > 0) |
1161 | | g_cacheLineSize = cacheLineSize; |
1162 | | #endif |
1163 | | |
1164 | | if (g_cacheLineSize == 0) |
1165 | | g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; |
1166 | | |
1167 | | #endif // CRYPTOPP_DISABLE_ASM |
1168 | | |
1169 | | *const_cast<volatile bool*>(&g_ArmDetectionDone) = true; |
1170 | | } |
1171 | | |
1172 | | // *************************** PowerPC and PowerPC64 *************************** |
1173 | | |
1174 | | #elif (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) |
1175 | | |
1176 | | bool CRYPTOPP_SECTION_INIT g_PowerPcDetectionDone = false; |
1177 | | bool CRYPTOPP_SECTION_INIT g_hasAltivec = false; |
1178 | | bool CRYPTOPP_SECTION_INIT g_hasPower7 = false; |
1179 | | bool CRYPTOPP_SECTION_INIT g_hasPower8 = false; |
1180 | | bool CRYPTOPP_SECTION_INIT g_hasPower9 = false; |
1181 | | bool CRYPTOPP_SECTION_INIT g_hasAES = false; |
1182 | | bool CRYPTOPP_SECTION_INIT g_hasPMULL = false; |
1183 | | bool CRYPTOPP_SECTION_INIT g_hasSHA256 = false; |
1184 | | bool CRYPTOPP_SECTION_INIT g_hasSHA512 = false; |
1185 | | bool CRYPTOPP_SECTION_INIT g_hasDARN = false; |
1186 | | word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; |
1187 | | |
1188 | | extern bool CPU_ProbeAltivec(); |
1189 | | extern bool CPU_ProbePower7(); |
1190 | | extern bool CPU_ProbePower8(); |
1191 | | extern bool CPU_ProbePower9(); |
1192 | | extern bool CPU_ProbeAES(); |
1193 | | extern bool CPU_ProbePMULL(); |
1194 | | extern bool CPU_ProbeSHA256(); |
1195 | | extern bool CPU_ProbeSHA512(); |
1196 | | extern bool CPU_ProbeDARN(); |
1197 | | |
1198 | | // AIX defines. We used to just call __power_7_andup() |
1199 | | // and friends but at Power9, too many compilers were |
1200 | | // missing __power_9_andup(). Instead we switched to |
1201 | | // a pattern similar to OpenSSL caps testing. |
1202 | | #ifndef __power_6_andup |
1203 | | # define __power_6_andup() __power_set(0xffffffffU<<14) |
1204 | | #endif |
1205 | | #ifndef __power_7_andup |
1206 | | # define __power_7_andup() __power_set(0xffffffffU<<15) |
1207 | | #endif |
1208 | | #ifndef __power_8_andup |
1209 | | # define __power_8_andup() __power_set(0xffffffffU<<16) |
1210 | | #endif |
1211 | | #ifndef __power_9_andup |
1212 | | # define __power_9_andup() __power_set(0xffffffffU<<17) |
1213 | | #endif |
1214 | | |
1215 | | // AIX first supported Altivec at Power6, though it |
1216 | | // was available much earlier for other vendors. |
1217 | | inline bool CPU_QueryAltivec() |
1218 | | { |
1219 | | #if defined(__linux__) && defined(PPC_FEATURE_HAS_ALTIVEC) |
1220 | | if ((getauxval(AT_HWCAP) & PPC_FEATURE_HAS_ALTIVEC) != 0) |
1221 | | return true; |
1222 | | #elif defined(_AIX) |
1223 | | if (__power_6_andup() != 0) |
1224 | | return true; |
1225 | | #elif defined(__APPLE__) && defined(__POWERPC__) |
1226 | | unsigned int unused, arch; |
1227 | | GetAppleMachineInfo(unused, unused, arch); |
1228 | | return arch == AppleMachineInfo::PowerMac; |
1229 | | #elif defined(__FreeBSD__) && defined(PPC_FEATURE_HAS_ALTIVEC) |
1230 | | unsigned long cpufeatures; |
1231 | | if (elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures)) == 0) |
1232 | | if ((cpufeatures & PPC_FEATURE_HAS_ALTIVEC) != 0) |
1233 | | return true; |
1234 | | #endif |
1235 | | return false; |
1236 | | } |
1237 | | |
1238 | | inline bool CPU_QueryPower7() |
1239 | | { |
1240 | | // Power7 and ISA 2.06 |
1241 | | #if defined(__linux__) && defined(PPC_FEATURE_ARCH_2_06) |
1242 | | if ((getauxval(AT_HWCAP) & PPC_FEATURE_ARCH_2_06) != 0) |
1243 | | return true; |
1244 | | #elif defined(_AIX) |
1245 | | if (__power_7_andup() != 0) |
1246 | | return true; |
1247 | | #elif defined(__FreeBSD__) && defined(PPC_FEATURE_ARCH_2_06) |
1248 | | unsigned long cpufeatures; |
1249 | | if (elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures)) == 0) |
1250 | | if ((cpufeatures & PPC_FEATURE_ARCH_2_06) != 0) |
1251 | | return true; |
1252 | | #endif |
1253 | | return false; |
1254 | | } |
1255 | | |
1256 | | inline bool CPU_QueryPower8() |
1257 | | { |
1258 | | // Power8 and ISA 2.07 provide in-core crypto. |
1259 | | #if defined(__linux__) && defined(PPC_FEATURE2_ARCH_2_07) |
1260 | | if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_2_07) != 0) |
1261 | | return true; |
1262 | | #elif defined(_AIX) |
1263 | | if (__power_8_andup() != 0) |
1264 | | return true; |
1265 | | #elif defined(__FreeBSD__) && defined(PPC_FEATURE2_ARCH_2_07) |
1266 | | unsigned long cpufeatures; |
1267 | | if (elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures)) == 0) |
1268 | | if ((cpufeatures & PPC_FEATURE_ARCH_2_07) != 0) |
1269 | | return true; |
1270 | | #endif |
1271 | | return false; |
1272 | | } |
1273 | | |
1274 | | inline bool CPU_QueryPower9() |
1275 | | { |
1276 | | // Power9 and ISA 3.0. |
1277 | | #if defined(__linux__) && defined(PPC_FEATURE2_ARCH_3_00) |
1278 | | if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_3_00) != 0) |
1279 | | return true; |
1280 | | #elif defined(_AIX) |
1281 | | if (__power_9_andup() != 0) |
1282 | | return true; |
1283 | | #elif defined(__FreeBSD__) && defined(PPC_FEATURE2_ARCH_3_00) |
1284 | | unsigned long cpufeatures; |
1285 | | if (elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures)) == 0) |
1286 | | if ((cpufeatures & PPC_FEATURE_ARCH2_3_00) != 0) |
1287 | | return true; |
1288 | | #endif |
1289 | | return false; |
1290 | | } |
1291 | | |
1292 | | inline bool CPU_QueryAES() |
1293 | | { |
1294 | | // Power8 and ISA 2.07 provide in-core crypto. Glibc |
1295 | | // 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO. |
1296 | | #if defined(__linux__) && defined(PPC_FEATURE2_VEC_CRYPTO) |
1297 | | if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0) |
1298 | | return true; |
1299 | | #elif defined(_AIX) |
1300 | | if (__power_8_andup() != 0) |
1301 | | return true; |
1302 | | #elif defined(__FreeBSD__) && defined(PPC_FEATURE2_HAS_VEC_CRYPTO) |
1303 | | unsigned long cpufeatures; |
1304 | | if (elf_aux_info(AT_HWCAP2, &cpufeatures, sizeof(cpufeatures)) == 0) |
1305 | | if ((cpufeatures & PPC_FEATURE2_HAS_VEC_CRYPTO != 0) |
1306 | | return true; |
1307 | | #endif |
1308 | | return false; |
1309 | | } |
1310 | | |
1311 | | inline bool CPU_QueryPMULL() |
1312 | | { |
1313 | | // Power8 and ISA 2.07 provide in-core crypto. Glibc |
1314 | | // 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO. |
1315 | | #if defined(__linux__) && defined(PPC_FEATURE2_VEC_CRYPTO) |
1316 | | if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0) |
1317 | | return true; |
1318 | | #elif defined(_AIX) |
1319 | | if (__power_8_andup() != 0) |
1320 | | return true; |
1321 | | #elif defined(__FreeBSD__) && defined(PPC_FEATURE2_HAS_VEC_CRYPTO) |
1322 | | unsigned long cpufeatures; |
1323 | | if (elf_aux_info(AT_HWCAP2, &cpufeatures, sizeof(cpufeatures)) == 0) |
1324 | | if ((cpufeatures & PPC_FEATURE2_HAS_VEC_CRYPTO != 0) |
1325 | | return true; |
1326 | | #endif |
1327 | | return false; |
1328 | | } |
1329 | | |
1330 | | inline bool CPU_QuerySHA256() |
1331 | | { |
1332 | | // Power8 and ISA 2.07 provide in-core crypto. Glibc |
1333 | | // 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO. |
1334 | | #if defined(__linux__) && defined(PPC_FEATURE2_VEC_CRYPTO) |
1335 | | if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0) |
1336 | | return true; |
1337 | | #elif defined(_AIX) |
1338 | | if (__power_8_andup() != 0) |
1339 | | return true; |
1340 | | #elif defined(__FreeBSD__) && defined(PPC_FEATURE2_HAS_VEC_CRYPTO) |
1341 | | unsigned long cpufeatures; |
1342 | | if (elf_aux_info(AT_HWCAP2, &cpufeatures, sizeof(cpufeatures)) == 0) |
1343 | | if ((cpufeatures & PPC_FEATURE2_HAS_VEC_CRYPTO != 0) |
1344 | | return true; |
1345 | | #endif |
1346 | | return false; |
1347 | | } |
1348 | | inline bool CPU_QuerySHA512() |
1349 | | { |
1350 | | // Power8 and ISA 2.07 provide in-core crypto. Glibc |
1351 | | // 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO. |
1352 | | #if defined(__linux__) && defined(PPC_FEATURE2_VEC_CRYPTO) |
1353 | | if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0) |
1354 | | return true; |
1355 | | #elif defined(_AIX) |
1356 | | if (__power_8_andup() != 0) |
1357 | | return true; |
1358 | | #elif defined(__FreeBSD__) && defined(PPC_FEATURE2_HAS_VEC_CRYPTO) |
1359 | | unsigned long cpufeatures; |
1360 | | if (elf_aux_info(AT_HWCAP2, &cpufeatures, sizeof(cpufeatures)) == 0) |
1361 | | if ((cpufeatures & PPC_FEATURE2_HAS_VEC_CRYPTO != 0) |
1362 | | return true; |
1363 | | #endif |
1364 | | return false; |
1365 | | } |
1366 | | |
1367 | | // Power9 random number generator |
1368 | | inline bool CPU_QueryDARN() |
1369 | | { |
1370 | | // Power9 and ISA 3.0 provide DARN. It looks like |
1371 | | // Glibc offers PPC_FEATURE2_DARN. |
1372 | | #if defined(__linux__) && defined(PPC_FEATURE2_ARCH_3_00) |
1373 | | if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_3_00) != 0) |
1374 | | return true; |
1375 | | #elif defined(_AIX) |
1376 | | if (__power_9_andup() != 0) |
1377 | | return true; |
1378 | | #elif defined(__FreeBSD__) && defined(PPC_FEATURE2_ARCH_3_00) |
1379 | | unsigned long cpufeatures; |
1380 | | if (elf_aux_info(AT_HWCAP2, &cpufeatures, sizeof(cpufeatures)) == 0) |
1381 | | if ((cpufeatures & PPC_FEATURE2_ARCH_3_00) != 0) |
1382 | | return true; |
1383 | | #endif |
1384 | | return false; |
1385 | | } |
1386 | | |
1387 | | void DetectPowerPcFeatures() |
1388 | | { |
1389 | | // GCC 10 is giving us trouble in CPU_ProbePower9() and CPU_ProbeDARN(). |
1390 | | // GCC is generating POWER9 instructions on POWER8 for ppc_power9.cpp. |
1391 | | // The compiler idiots did not think through the consequences of |
1392 | | // requiring us to use -mcpu=power9 to unlock the ISA. Epic fail. |
1393 | | // https://github.com/weidai11/cryptopp/issues/986 |
1394 | | |
1395 | | #ifndef CRYPTOPP_DISABLE_ASM |
1396 | | |
1397 | | // The CPU_ProbeXXX's return false for OSes which |
1398 | | // can't tolerate SIGILL-based probes, like Apple |
1399 | | g_hasAltivec = CPU_QueryAltivec() || CPU_ProbeAltivec(); |
1400 | | g_hasPower7 = CPU_QueryPower7() || CPU_ProbePower7(); |
1401 | | g_hasPower8 = CPU_QueryPower8() || CPU_ProbePower8(); |
1402 | | g_hasPower9 = CPU_QueryPower9() || CPU_ProbePower9(); |
1403 | | g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL(); |
1404 | | g_hasAES = CPU_QueryAES() || CPU_ProbeAES(); |
1405 | | g_hasSHA256 = CPU_QuerySHA256() || CPU_ProbeSHA256(); |
1406 | | g_hasSHA512 = CPU_QuerySHA512() || CPU_ProbeSHA512(); |
1407 | | g_hasDARN = CPU_QueryDARN() || CPU_ProbeDARN(); |
1408 | | |
1409 | | #if defined(_AIX) && defined(SC_L1C_DLS) |
1410 | | // /usr/include/sys/systemcfg.h |
1411 | | int cacheLineSize = getsystemcfg(SC_L1C_DLS); |
1412 | | if (cacheLineSize > 0) |
1413 | | g_cacheLineSize = cacheLineSize; |
1414 | | #elif defined(_SC_LEVEL1_DCACHE_LINESIZE) |
1415 | | // Glibc does not implement on some platforms. The runtime returns 0 instead of error. |
1416 | | // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/sysconf.c |
1417 | | int cacheLineSize = (int)sysconf(_SC_LEVEL1_DCACHE_LINESIZE); |
1418 | | if (cacheLineSize > 0) |
1419 | | g_cacheLineSize = cacheLineSize; |
1420 | | #endif |
1421 | | |
1422 | | if (g_cacheLineSize == 0) |
1423 | | g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; |
1424 | | |
1425 | | #endif // CRYPTOPP_DISABLE_ASM |
1426 | | |
1427 | | *const_cast<volatile bool*>(&g_PowerPcDetectionDone) = true; |
1428 | | } |
1429 | | |
1430 | | #endif |
1431 | | NAMESPACE_END |
1432 | | |
1433 | | // *************************** C++ Static Initialization *************************** |
1434 | | |
1435 | | ANONYMOUS_NAMESPACE_BEGIN |
1436 | | |
1437 | | class InitCpu |
1438 | | { |
1439 | | public: |
1440 | | InitCpu() |
1441 | 10 | { |
1442 | 10 | #if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 |
1443 | 10 | CryptoPP::DetectX86Features(); |
1444 | | #elif CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8 |
1445 | | CryptoPP::DetectArmFeatures(); |
1446 | | #elif CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 |
1447 | | CryptoPP::DetectPowerPcFeatures(); |
1448 | | #endif |
1449 | 10 | } |
1450 | | }; |
1451 | | |
1452 | | // This is not really needed because HasSSE() and friends can dynamically initialize. |
1453 | | // Everything depends on CPU features so we initialize it once at load time. |
1454 | | // Dynamic initialization will be used if init priorities are not available. |
1455 | | |
1456 | | #if HAVE_GCC_INIT_PRIORITY |
1457 | | const InitCpu s_init __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 10))) = InitCpu(); |
1458 | | #elif HAVE_MSC_INIT_PRIORITY |
1459 | | #pragma warning(disable: 4075) |
1460 | | #pragma init_seg(".CRT$XCU") |
1461 | | const InitCpu s_init; |
1462 | | #pragma warning(default: 4075) |
1463 | | #elif HAVE_XLC_INIT_PRIORITY |
1464 | | // XLC needs constant, not a define |
1465 | | #pragma priority(270) |
1466 | | const InitCpu s_init; |
1467 | | #else |
1468 | | const InitCpu s_init; |
1469 | | #endif |
1470 | | |
1471 | | ANONYMOUS_NAMESPACE_END |
1472 | | |
1473 | | #endif // CRYPTOPP_IMPORTS |