Botan 3.6.1
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,2023 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 <iosfwd>
13#include <string>
14#include <vector>
15
16namespace Botan {
17
18#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
19 defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
20
21 #define BOTAN_CPUID_HAS_DETECTION
22
23#endif
24
25/**
26* A class handling runtime CPU feature detection. It is limited to
27* just the features necessary to implement CPU specific code in Botan,
28* rather than being a general purpose utility.
29*
30* This class supports:
31*
32* - x86 features using CPUID. x86 is also the only processor with
33* accurate cache line detection currently.
34*
35* - PowerPC AltiVec detection on Linux, NetBSD, OpenBSD, and macOS
36*
37* - ARM NEON and crypto extensions detection. On Linux and Android
38* systems which support getauxval, that is used to access CPU
39* feature information. Otherwise a relatively portable but
40* thread-unsafe mechanism involving executing probe functions which
41* catching SIGILL signal is used.
42*/
44 public:
45 /**
46 * Probe the CPU and see what extensions are supported
47 */
48 static void initialize();
49
50 /**
51 * Return a possibly empty string containing list of known CPU
52 * extensions. Each name will be seperated by a space, and the ordering
53 * will be arbitrary. This list only contains values that are useful to
54 * Botan (for example FMA instructions are not checked).
55 *
56 * Example outputs "sse2 ssse3 rdtsc", "neon arm_aes", "altivec"
57 */
58 static std::string to_string();
59
60 static bool is_little_endian() {
61#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
62 return true;
63#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
64 return false;
65#else
66 return !has_cpuid_bit(CPUID_IS_BIG_ENDIAN_BIT);
67#endif
68 }
69
70 static bool is_big_endian() {
71#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
72 return true;
73#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
74 return false;
75#else
76 return has_cpuid_bit(CPUID_IS_BIG_ENDIAN_BIT);
77#endif
78 }
79
80 /**
81 * Return true if a 4x32 SIMD instruction set is available
82 * (SSE2, NEON, or Altivec/VMX)
83 */
84 static bool has_simd_32() {
85#if defined(BOTAN_TARGET_SUPPORTS_SSE2)
86 return CPUID::has_sse2();
87#elif defined(BOTAN_TARGET_SUPPORTS_ALTIVEC)
88 return CPUID::has_altivec();
89#elif defined(BOTAN_TARGET_SUPPORTS_NEON)
90 return CPUID::has_neon();
91#else
92 return false;
93#endif
94 }
95
96 enum CPUID_bits : uint32_t {
97#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
98 // These values have no relation to cpuid bitfields
99
100 // SIMD instruction sets
101 CPUID_SSE2_BIT = (1U << 0),
102 CPUID_SSSE3_BIT = (1U << 1),
103 CPUID_AVX2_BIT = (1U << 2),
104 CPUID_AVX512_BIT = (1U << 3),
105
106 // Misc useful instructions
107 CPUID_RDTSC_BIT = (1U << 10),
108 CPUID_ADX_BIT = (1U << 11),
109 CPUID_BMI_BIT = (1U << 12),
110 CPUID_GFNI_BIT = (1U << 13),
111
112 // Crypto-specific ISAs
113 CPUID_AESNI_BIT = (1U << 16),
114 CPUID_CLMUL_BIT = (1U << 17),
115 CPUID_RDRAND_BIT = (1U << 18),
116 CPUID_RDSEED_BIT = (1U << 19),
117 CPUID_SHA_BIT = (1U << 20),
118 CPUID_AVX512_AES_BIT = (1U << 21),
119 CPUID_AVX512_CLMUL_BIT = (1U << 22),
120 CPUID_AVX2_AES_BIT = (1U << 23),
121 CPUID_AVX2_CLMUL_BIT = (1U << 24),
122 CPUID_SHA512_BIT = (1U << 25),
123 CPUID_SM3_BIT = (1U << 26),
124 CPUID_SM4_BIT = (1U << 27),
125#endif
126
127#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
128 CPUID_ALTIVEC_BIT = (1U << 0),
129 CPUID_POWER_CRYPTO_BIT = (1U << 1),
130 CPUID_DARN_BIT = (1U << 2),
131#endif
132
133#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
134 CPUID_ARM_NEON_BIT = (1U << 0),
135 CPUID_ARM_SVE_BIT = (1U << 1),
136 CPUID_ARM_AES_BIT = (1U << 16),
137 CPUID_ARM_PMULL_BIT = (1U << 17),
138 CPUID_ARM_SHA1_BIT = (1U << 18),
139 CPUID_ARM_SHA2_BIT = (1U << 19),
140 CPUID_ARM_SHA3_BIT = (1U << 20),
141 CPUID_ARM_SHA2_512_BIT = (1U << 21),
142 CPUID_ARM_SM3_BIT = (1U << 22),
143 CPUID_ARM_SM4_BIT = (1U << 23),
144#endif
145
146 CPUID_IS_BIG_ENDIAN_BIT = (1U << 30),
147 CPUID_INITIALIZED_BIT = (1U << 31)
148 };
149
150#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
151 /**
152 * Check if the processor supports AltiVec/VMX
153 */
154 static bool has_altivec() { return has_cpuid_bit(CPUID_ALTIVEC_BIT); }
155
156 /**
157 * Check if the processor supports POWER8 crypto extensions
158 */
159 static bool has_power_crypto() { return has_cpuid_bit(CPUID_POWER_CRYPTO_BIT); }
160
161 /**
162 * Check if the processor supports POWER9 DARN RNG
163 */
164 static bool has_darn_rng() { return has_cpuid_bit(CPUID_DARN_BIT); }
165
166#endif
167
168#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
169 /**
170 * Check if the processor supports NEON SIMD
171 */
172 static bool has_neon() { return has_cpuid_bit(CPUID_ARM_NEON_BIT); }
173
174 /**
175 * Check if the processor supports ARMv8 SVE
176 */
177 static bool has_arm_sve() { return has_cpuid_bit(CPUID_ARM_SVE_BIT); }
178
179 /**
180 * Check if the processor supports ARMv8 SHA1
181 */
182 static bool has_arm_sha1() { return has_cpuid_bit(CPUID_ARM_SHA1_BIT); }
183
184 /**
185 * Check if the processor supports ARMv8 SHA2
186 */
187 static bool has_arm_sha2() { return has_cpuid_bit(CPUID_ARM_SHA2_BIT); }
188
189 /**
190 * Check if the processor supports ARMv8 AES
191 */
192 static bool has_arm_aes() { return has_cpuid_bit(CPUID_ARM_AES_BIT); }
193
194 /**
195 * Check if the processor supports ARMv8 PMULL
196 */
197 static bool has_arm_pmull() { return has_cpuid_bit(CPUID_ARM_PMULL_BIT); }
198
199 /**
200 * Check if the processor supports ARMv8 SHA-512
201 */
202 static bool has_arm_sha2_512() { return has_cpuid_bit(CPUID_ARM_SHA2_512_BIT); }
203
204 /**
205 * Check if the processor supports ARMv8 SHA-3
206 */
207 static bool has_arm_sha3() { return has_cpuid_bit(CPUID_ARM_SHA3_BIT); }
208
209 /**
210 * Check if the processor supports ARMv8 SM3
211 */
212 static bool has_arm_sm3() { return has_cpuid_bit(CPUID_ARM_SM3_BIT); }
213
214 /**
215 * Check if the processor supports ARMv8 SM4
216 */
217 static bool has_arm_sm4() { return has_cpuid_bit(CPUID_ARM_SM4_BIT); }
218
219#endif
220
221#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
222
223 /**
224 * Check if the processor supports RDTSC
225 */
226 static bool has_rdtsc() { return has_cpuid_bit(CPUID_RDTSC_BIT); }
227
228 /**
229 * Check if the processor supports SSE2
230 */
231 static bool has_sse2() { return has_cpuid_bit(CPUID_SSE2_BIT); }
232
233 /**
234 * Check if the processor supports SSSE3
235 */
236 static bool has_ssse3() { return has_cpuid_bit(CPUID_SSSE3_BIT); }
237
238 /**
239 * Check if the processor supports AVX2
240 */
241 static bool has_avx2() { return has_cpuid_bit(CPUID_AVX2_BIT); }
242
243 /**
244 * Check if the processor supports our AVX-512 minimum profile
245 *
246 * Namely AVX-512 F, DQ, BW, VL, IFMA, VBMI, VBMI2, BITALG
247 */
248 static bool has_avx512() { return has_cpuid_bit(CPUID_AVX512_BIT); }
249
250 /**
251 * Check if the processor supports AVX-512 AES (VAES)
252 *
253 * Only set if the baseline AVX-512 profile is also satisfied
254 */
255 static bool has_avx512_aes() { return has_cpuid_bit(CPUID_AVX512_AES_BIT); }
256
257 /**
258 * Check if the processor supports AVX2 AES (VAES)
259 */
260 static bool has_avx2_vaes() { return has_cpuid_bit(CPUID_AVX2_AES_BIT); }
261
262 /**
263 * Check if the processor supports AVX2 CLMUL
264 */
265 static bool has_avx2_clmul() { return has_cpuid_bit(CPUID_AVX2_CLMUL_BIT); }
266
267 /**
268 * Check if the processor supports AVX-512 VPCLMULQDQ
269 */
270 static bool has_avx512_clmul() { return has_cpuid_bit(CPUID_AVX512_CLMUL_BIT); }
271
272 /**
273 * Check if the processor supports BMI2 (and BMI1)
274 */
275 static bool has_bmi2() { return has_cpuid_bit(CPUID_BMI_BIT); }
276
277 /**
278 * Check if the processor supports GFNI
279 *
280 * A few Atom processors supported GFNI only for SSE; we gate this bit
281 * on the processor also supporting GFNI-AVX2
282 */
283 static bool has_gfni() { return has_cpuid_bit(CPUID_GFNI_BIT); }
284
285 /**
286 * Check if the processor supports AES-NI
287 */
288 static bool has_aes_ni() { return has_cpuid_bit(CPUID_AESNI_BIT); }
289
290 /**
291 * Check if the processor supports CLMUL
292 */
293 static bool has_clmul() { return has_cpuid_bit(CPUID_CLMUL_BIT); }
294
295 /**
296 * Check if the processor supports Intel SHA extension
297 */
298 static bool has_intel_sha() { return has_cpuid_bit(CPUID_SHA_BIT); }
299
300 /**
301 * Check if the processor supports Intel SHA-512 extension
302 */
303 static bool has_intel_sha512() { return has_cpuid_bit(CPUID_SHA512_BIT); }
304
305 /**
306 * Check if the processor supports Intel SM3
307 */
308 static bool has_intel_sm3() { return has_cpuid_bit(CPUID_SM3_BIT); }
309
310 /**
311 * Check if the processor supports Intel SM4
312 */
313 static bool has_intel_sm4() { return has_cpuid_bit(CPUID_SM4_BIT); }
314
315 /**
316 * Check if the processor supports ADX extension
317 */
318 static bool has_adx() { return has_cpuid_bit(CPUID_ADX_BIT); }
319
320 /**
321 * Check if the processor supports RDRAND
322 */
323 static bool has_rdrand() { return has_cpuid_bit(CPUID_RDRAND_BIT); }
324
325 /**
326 * Check if the processor supports RDSEED
327 */
328 static bool has_rdseed() { return has_cpuid_bit(CPUID_RDSEED_BIT); }
329#endif
330
331 /**
332 * Check if the processor supports byte-level vector permutes
333 * (SSSE3, NEON, Altivec)
334 */
335 static bool has_vperm() {
336#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
337 return has_ssse3();
338#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
339 return has_neon();
340#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
341 return has_altivec();
342#else
343 return false;
344#endif
345 }
346
347 /**
348 * Check if the processor supports hardware AES instructions
349 */
350 static bool has_hw_aes() {
351#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
352 return has_aes_ni();
353#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
354 return has_arm_aes();
355#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
356 return has_power_crypto();
357#else
358 return false;
359#endif
360 }
361
362 /**
363 * Check if the processor supports carryless multiply
364 * (CLMUL, PMULL)
365 */
367#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
368 return has_clmul();
369#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
370 return has_arm_pmull();
371#elif defined(BOTAN_TARGET_ARCH_IS_PPC64)
372 return has_power_crypto();
373#else
374 return false;
375#endif
376 }
377
378 /*
379 * Clear a CPUID bit
380 * Call CPUID::initialize to reset
381 *
382 * This is only exposed for testing, don't use unless you know
383 * what you are doing.
384 */
385 static void clear_cpuid_bit(CPUID_bits bit) { state().clear_cpuid_bit(static_cast<uint32_t>(bit)); }
386
387 /*
388 * Don't call this function, use CPUID::has_xxx above
389 * It is only exposed for the tests.
390 */
391 static bool has_cpuid_bit(CPUID_bits elem) {
392 const uint32_t elem32 = static_cast<uint32_t>(elem);
393 return state().has_bit(elem32);
394 }
395
396 static std::vector<CPUID::CPUID_bits> bit_from_string(std::string_view tok);
397
398 private:
399 /**
400 * A common helper for the various CPUID implementations
401 */
402 template <typename T>
403 static inline uint32_t if_set(uint64_t cpuid, T flag, CPUID::CPUID_bits bit, uint32_t allowed) {
404 const uint64_t flag64 = static_cast<uint64_t>(flag);
405 if((cpuid & flag64) == flag64) {
406 return (bit & allowed);
407 } else {
408 return 0;
409 }
410 }
411
412 struct CPUID_Data {
413 public:
414 CPUID_Data();
415
416 CPUID_Data(const CPUID_Data& other) = default;
417 CPUID_Data& operator=(const CPUID_Data& other) = default;
418
419 void clear_cpuid_bit(uint32_t bit) { m_processor_features &= ~bit; }
420
421 bool has_bit(uint32_t bit) const { return (m_processor_features & bit) == bit; }
422
423 private:
424#if defined(BOTAN_CPUID_HAS_DETECTION)
425 static uint32_t detect_cpu_features(uint32_t allowed_bits);
426#endif
427
428 uint32_t m_processor_features;
429 };
430
431 static CPUID_Data& state() {
432 static CPUID::CPUID_Data g_cpuid;
433 return g_cpuid;
434 }
435};
436
437} // namespace Botan
438
439#endif
static bool has_vperm()
Definition cpuid.h:335
static bool is_little_endian()
Definition cpuid.h:60
static bool is_big_endian()
Definition cpuid.h:70
static bool has_simd_32()
Definition cpuid.h:84
static bool has_cpuid_bit(CPUID_bits elem)
Definition cpuid.h:391
static bool has_carryless_multiply()
Definition cpuid.h:366
static void clear_cpuid_bit(CPUID_bits bit)
Definition cpuid.h:385
static bool has_hw_aes()
Definition cpuid.h:350
int(* final)(unsigned char *, CTX *)
#define BOTAN_TEST_API
Definition compiler.h:51
FE_25519 T
Definition ge.cpp:34