Botan 2.19.5 Crypto and TLS for C&

cpuid.h
Go to the documentation of this file.
1/*
2* Runtime CPU detection
3* (C) 2009,2010,2013,2017 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#ifndef BOTAN_CPUID_H_
9#define BOTAN_CPUID_H_
10
11#include <botan/types.h>
12#include <vector>
13#include <string>
14#include <iosfwd>
15
16 BOTAN_FUTURE_INTERNAL_HEADER(cpuid.h)
17
18namespace Botan {
19
20/**
21* A class handling runtime CPU feature detection. It is limited to
22* just the features necessary to implement CPU specific code in Botan,
23* rather than being a general purpose utility.
24*
25* This class supports:
26*
27* - x86 features using CPUID. x86 is also the only processor with
28* accurate cache line detection currently.
29*
30* - PowerPC AltiVec detection on Linux, NetBSD, OpenBSD, and macOS
31*
32* - ARM NEON and crypto extensions detection. On Linux and Android
33* systems which support getauxval, that is used to access CPU
34* feature information. Otherwise a relatively portable but
35* thread-unsafe mechanism involving executing probe functions which
36* catching SIGILL signal is used.
37*/
38 class BOTAN_PUBLIC_API(2,1) CPUID final
39 {
40 public:
41 /**
42 * Probe the CPU and see what extensions are supported
43 */
44 static void initialize();
45
46 static bool has_simd_32();
47
48 /**
49 * Deprecated equivalent to
50 * o << "CPUID flags: " << CPUID::to_string() << "\n";
51 */
52 BOTAN_DEPRECATED("Use CPUID::to_string")
53 static void print(std::ostream& o);
54
55 /**
56 * Return a possibly empty string containing list of known CPU
57 * extensions. Each name will be seperated by a space, and the ordering
58 * will be arbitrary. This list only contains values that are useful to
59 * Botan (for example FMA instructions are not checked).
60 *
61 * Example outputs "sse2 ssse3 rdtsc", "neon arm_aes", "altivec"
62 */
63 static std::string to_string();
64
65 /**
66 * Return a best guess of the cache line size
67 */
68 static size_t cache_line_size()
69 {
70 return state().cache_line_size();
71 }
72
73 static bool is_little_endian()
74 {
75#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
76 return true;
77#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
78 return false;
79#else
80 return state().endian_status() == Endian_Status::Little;
81#endif
82 }
83
84 static bool is_big_endian()
85 {
86#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
87 return true;
88#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
89 return false;
90#else
91 return state().endian_status() == Endian_Status::Big;
92#endif
93 }
94
95 enum CPUID_bits : uint64_t {
96#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
97 // These values have no relation to cpuid bitfields
98
99 // SIMD instruction sets
100 CPUID_SSE2_BIT = (1ULL << 0),
101 CPUID_SSSE3_BIT = (1ULL << 1),
102 CPUID_SSE41_BIT = (1ULL << 2),
103 CPUID_SSE42_BIT = (1ULL << 3),
104 CPUID_AVX2_BIT = (1ULL << 4),
105 CPUID_AVX512F_BIT = (1ULL << 5),
106
107 CPUID_AVX512DQ_BIT = (1ULL << 6),
108 CPUID_AVX512BW_BIT = (1ULL << 7),
109
110 // Ice Lake profile: AVX-512 F, DQ, BW, IFMA, VBMI, VBMI2, BITALG
111 CPUID_AVX512_ICL_BIT = (1ULL << 11),
112
113 // Crypto-specific ISAs
114 CPUID_AESNI_BIT = (1ULL << 16),
115 CPUID_CLMUL_BIT = (1ULL << 17),
116 CPUID_RDRAND_BIT = (1ULL << 18),
117 CPUID_RDSEED_BIT = (1ULL << 19),
118 CPUID_SHA_BIT = (1ULL << 20),
119 CPUID_AVX512_AES_BIT = (1ULL << 21),
120 CPUID_AVX512_CLMUL_BIT = (1ULL << 22),
121
122 // Misc useful instructions
123 CPUID_RDTSC_BIT = (1ULL << 48),
124 CPUID_ADX_BIT = (1ULL << 49),
125 CPUID_BMI1_BIT = (1ULL << 50),
126 CPUID_BMI2_BIT = (1ULL << 51),
127#endif
128
129#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
130 CPUID_ALTIVEC_BIT = (1ULL << 0),
131 CPUID_POWER_CRYPTO_BIT = (1ULL << 1),
132 CPUID_DARN_BIT = (1ULL << 2),
133#endif
134
135#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
136 CPUID_ARM_NEON_BIT = (1ULL << 0),
137 CPUID_ARM_SVE_BIT = (1ULL << 1),
138 CPUID_ARM_AES_BIT = (1ULL << 16),
139 CPUID_ARM_PMULL_BIT = (1ULL << 17),
140 CPUID_ARM_SHA1_BIT = (1ULL << 18),
141 CPUID_ARM_SHA2_BIT = (1ULL << 19),
142 CPUID_ARM_SHA3_BIT = (1ULL << 20),
143 CPUID_ARM_SHA2_512_BIT = (1ULL << 21),
144 CPUID_ARM_SM3_BIT = (1ULL << 22),
145 CPUID_ARM_SM4_BIT = (1ULL << 23),
146#endif
147
148 CPUID_INITIALIZED_BIT = (1ULL << 63)
149 };
150
151#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
152 /**
153 * Check if the processor supports AltiVec/VMX
154 */
155 static bool has_altivec()
156 { return has_cpuid_bit(CPUID_ALTIVEC_BIT); }
157
158 /**
159 * Check if the processor supports POWER8 crypto extensions
160 */
161 static bool has_power_crypto()
162 { return has_cpuid_bit(CPUID_POWER_CRYPTO_BIT); }
163
164 /**
165 * Check if the processor supports POWER9 DARN RNG
166 */
167 static bool has_darn_rng()
168 { return has_cpuid_bit(CPUID_DARN_BIT); }
169
170#endif
171
172#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
173 /**
174 * Check if the processor supports NEON SIMD
175 */
176 static bool has_neon()
177 { return has_cpuid_bit(CPUID_ARM_NEON_BIT); }
178
179 /**
180 * Check if the processor supports ARMv8 SVE
181 */
182 static bool has_arm_sve()
183 { return has_cpuid_bit(CPUID_ARM_SVE_BIT); }
184
185 /**
186 * Check if the processor supports ARMv8 SHA1
187 */
188 static bool has_arm_sha1()
189 { return has_cpuid_bit(CPUID_ARM_SHA1_BIT); }
190
191 /**
192 * Check if the processor supports ARMv8 SHA2
193 */
194 static bool has_arm_sha2()
195 { return has_cpuid_bit(CPUID_ARM_SHA2_BIT); }
196
197 /**
198 * Check if the processor supports ARMv8 AES
199 */
200 static bool has_arm_aes()
201 { return has_cpuid_bit(CPUID_ARM_AES_BIT); }
202
203 /**
204 * Check if the processor supports ARMv8 PMULL
205 */
206 static bool has_arm_pmull()
207 { return has_cpuid_bit(CPUID_ARM_PMULL_BIT); }
208
209 /**
210 * Check if the processor supports ARMv8 SHA-512
211 */
212 static bool has_arm_sha2_512()
213 { return has_cpuid_bit(CPUID_ARM_SHA2_512_BIT); }
214
215 /**
216 * Check if the processor supports ARMv8 SHA-3
217 */
218 static bool has_arm_sha3()
219 { return has_cpuid_bit(CPUID_ARM_SHA3_BIT); }
220
221 /**
222 * Check if the processor supports ARMv8 SM3
223 */
224 static bool has_arm_sm3()
225 { return has_cpuid_bit(CPUID_ARM_SM3_BIT); }
226
227 /**
228 * Check if the processor supports ARMv8 SM4
229 */
230 static bool has_arm_sm4()
231 { return has_cpuid_bit(CPUID_ARM_SM4_BIT); }
232
233#endif
234
235#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
236
237 /**
238 * Check if the processor supports RDTSC
239 */
240 static bool has_rdtsc()
241 { return has_cpuid_bit(CPUID_RDTSC_BIT); }
242
243 /**
244 * Check if the processor supports SSE2
245 */
246 static bool has_sse2()
247 { return has_cpuid_bit(CPUID_SSE2_BIT); }
248
249 /**
250 * Check if the processor supports SSSE3
251 */
252 static bool has_ssse3()
253 { return has_cpuid_bit(CPUID_SSSE3_BIT); }
254
255 /**
256 * Check if the processor supports SSE4.1
257 */
258 static bool has_sse41()
259 { return has_cpuid_bit(CPUID_SSE41_BIT); }
260
261 /**
262 * Check if the processor supports SSE4.2
263 */
264 static bool has_sse42()
265 { return has_cpuid_bit(CPUID_SSE42_BIT); }
266
267 /**
268 * Check if the processor supports AVX2
269 */
270 static bool has_avx2()
271 { return has_cpuid_bit(CPUID_AVX2_BIT); }
272
273 /**
274 * Check if the processor supports AVX-512F
275 */
276 static bool has_avx512f()
277 { return has_cpuid_bit(CPUID_AVX512F_BIT); }
278
279 /**
280 * Check if the processor supports AVX-512DQ
281 */
282 static bool has_avx512dq()
283 { return has_cpuid_bit(CPUID_AVX512DQ_BIT); }
284
285 /**
286 * Check if the processor supports AVX-512BW
287 */
288 static bool has_avx512bw()
289 { return has_cpuid_bit(CPUID_AVX512BW_BIT); }
290
291 /**
292 * Check if the processor supports AVX-512 Ice Lake profile
293 */
294 static bool has_avx512_icelake()
295 { return has_cpuid_bit(CPUID_AVX512_ICL_BIT); }
296
297 /**
298 * Check if the processor supports AVX-512 AES (VAES)
299 */
300 static bool has_avx512_aes()
301 { return has_cpuid_bit(CPUID_AVX512_AES_BIT); }
302
303 /**
304 * Check if the processor supports AVX-512 VPCLMULQDQ
305 */
306 static bool has_avx512_clmul()
307 { return has_cpuid_bit(CPUID_AVX512_CLMUL_BIT); }
308
309 /**
310 * Check if the processor supports BMI1
311 */
312 static bool has_bmi1()
313 { return has_cpuid_bit(CPUID_BMI1_BIT); }
314
315 /**
316 * Check if the processor supports BMI2
317 */
318 static bool has_bmi2()
319 { return has_cpuid_bit(CPUID_BMI2_BIT); }
320
321 /**
322 * Check if the processor supports AES-NI
323 */
324 static bool has_aes_ni()
325 { return has_cpuid_bit(CPUID_AESNI_BIT); }
326
327 /**
328 * Check if the processor supports CLMUL
329 */
330 static bool has_clmul()
331 { return has_cpuid_bit(CPUID_CLMUL_BIT); }
332
333 /**
334 * Check if the processor supports Intel SHA extension
335 */
336 static bool has_intel_sha()
337 { return has_cpuid_bit(CPUID_SHA_BIT); }
338
339 /**
340 * Check if the processor supports ADX extension
341 */
342 static bool has_adx()
343 { return has_cpuid_bit(CPUID_ADX_BIT); }
344
345 /**
346 * Check if the processor supports RDRAND
347 */
348 static bool has_rdrand()
349 { return has_cpuid_bit(CPUID_RDRAND_BIT); }
350
351 /**
352 * Check if the processor supports RDSEED
353 */
354 static bool has_rdseed()
355 { return has_cpuid_bit(CPUID_RDSEED_BIT); }
356#endif
357
358 /**
359 * Check if the processor supports byte-level vector permutes
360 * (SSSE3, NEON, Altivec)
361 */
362 static bool has_vperm()
363 {
364#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
365 return has_ssse3();
366#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
367 return has_neon();
368#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
369 return has_altivec();
370#else
371 return false;
372#endif
373 }
374
375 /**
376 * Check if the processor supports hardware AES instructions
377 */
378 static bool has_hw_aes()
379 {
380#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
381 return has_aes_ni();
382#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
383 return has_arm_aes();
384#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
385 return has_power_crypto();
386#else
387 return false;
388#endif
389 }
390
391 /**
392 * Check if the processor supports carryless multiply
393 * (CLMUL, PMULL)
394 */
395 static bool has_carryless_multiply()
396 {
397#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
398 return has_clmul();
399#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
400 return has_arm_pmull();
401#elif defined(BOTAN_TARGET_ARCH_IS_PPC64)
402 return has_power_crypto();
403#else
404 return false;
405#endif
406 }
407
408 /*
409 * Clear a CPUID bit
410 * Call CPUID::initialize to reset
411 *
412 * This is only exposed for testing, don't use unless you know
413 * what you are doing.
414 */
415 static void clear_cpuid_bit(CPUID_bits bit)
416 {
417 state().clear_cpuid_bit(static_cast<uint64_t>(bit));
418 }
419
420 /*
421 * Don't call this function, use CPUID::has_xxx above
422 * It is only exposed for the tests.
423 */
424 static bool has_cpuid_bit(CPUID_bits elem)
425 {
426 const uint64_t elem64 = static_cast<uint64_t>(elem);
427 return state().has_bit(elem64);
428 }
429
430 static std::vector<CPUID::CPUID_bits> bit_from_string(const std::string& tok);
431 private:
432 enum class Endian_Status : uint32_t {
433 Unknown = 0x00000000,
434 Big = 0x01234567,
435 Little = 0x67452301,
436 };
437
438 struct CPUID_Data
439 {
440 public:
441 CPUID_Data();
442
443 CPUID_Data(const CPUID_Data& other) = default;
444 CPUID_Data& operator=(const CPUID_Data& other) = default;
445
446 void clear_cpuid_bit(uint64_t bit)
447 {
448 m_processor_features &= ~bit;
449 }
450
451 bool has_bit(uint64_t bit) const
452 {
453 return (m_processor_features & bit) == bit;
454 }
455
456 uint64_t processor_features() const { return m_processor_features; }
457 Endian_Status endian_status() const { return m_endian_status; }
458 size_t cache_line_size() const { return m_cache_line_size; }
459
460 private:
461 static Endian_Status runtime_check_endian();
462
463#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \
464 defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
465 defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
466
467 static uint64_t detect_cpu_features(size_t* cache_line_size);
468
469#endif
470 uint64_t m_processor_features;
471 size_t m_cache_line_size;
472 Endian_Status m_endian_status;
473 };
474
475 static CPUID_Data& state()
476 {
477 static CPUID::CPUID_Data g_cpuid;
478 return g_cpuid;
479 }
480 };
481
482}
483
484#endif
Botan::CPUID
Definition: cpuid.h:39
Botan::CPUID::has_vperm
static bool has_vperm()
Definition: cpuid.h:362
Botan::CPUID::is_little_endian
static bool is_little_endian()
Definition: cpuid.h:73
Botan::CPUID::is_big_endian
static bool is_big_endian()
Definition: cpuid.h:84
Botan::CPUID::cache_line_size
static size_t cache_line_size()
Definition: cpuid.h:68
Botan::CPUID::has_cpuid_bit
static bool has_cpuid_bit(CPUID_bits elem)
Definition: cpuid.h:424
Botan::CPUID::has_carryless_multiply
static bool has_carryless_multiply()
Definition: cpuid.h:395
Botan::CPUID::CPUID_bits
CPUID_bits
Definition: cpuid.h:95
Botan::CPUID::clear_cpuid_bit
static void clear_cpuid_bit(CPUID_bits bit)
Definition: cpuid.h:415
Botan::CPUID::has_hw_aes
static bool has_hw_aes()
Definition: cpuid.h:378
final
int(* final)(unsigned char *, CTX *)
Definition: commoncrypto_hash.cpp:29
BOTAN_PUBLIC_API
#define BOTAN_PUBLIC_API(maj, min)
Definition: compiler.h:31
BOTAN_FUTURE_INTERNAL_HEADER
#define BOTAN_FUTURE_INTERNAL_HEADER(hdr)
Definition: compiler.h:136
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
Botan
Definition: alg_id.cpp:13
Botan::ErrorType::Unknown
@ Unknown