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