Botan 3.4.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 <iosfwd>
13#include <string>
14#include <vector>
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 public:
38 /**
39 * Probe the CPU and see what extensions are supported
40 */
41 static void initialize();
42
43 /**
44 * Return true if a 4x32 SIMD instruction set is available
45 * (SSE2, NEON, or Altivec/VMX)
46 */
47 static bool has_simd_32();
48
49 /**
50 * Return a possibly empty string containing list of known CPU
51 * extensions. Each name will be seperated by a space, and the ordering
52 * will be arbitrary. This list only contains values that are useful to
53 * Botan (for example FMA instructions are not checked).
54 *
55 * Example outputs "sse2 ssse3 rdtsc", "neon arm_aes", "altivec"
56 */
57 static std::string to_string();
58
59 static bool is_little_endian() {
60#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
61 return true;
62#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
63 return false;
64#else
65 return !has_cpuid_bit(CPUID_IS_BIG_ENDIAN_BIT);
66#endif
67 }
68
69 static bool is_big_endian() {
70#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
71 return true;
72#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
73 return false;
74#else
75 return has_cpuid_bit(CPUID_IS_BIG_ENDIAN_BIT);
76#endif
77 }
78
79 enum CPUID_bits : uint32_t {
80#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
81 // These values have no relation to cpuid bitfields
82
83 // SIMD instruction sets
84 CPUID_SSE2_BIT = (1U << 0),
85 CPUID_SSSE3_BIT = (1U << 1),
86 CPUID_AVX2_BIT = (1U << 2),
87 CPUID_AVX512_BIT = (1U << 3),
88
89 // Misc useful instructions
90 CPUID_RDTSC_BIT = (1U << 10),
91 CPUID_ADX_BIT = (1U << 11),
92 CPUID_BMI_BIT = (1U << 12),
93
94 // Crypto-specific ISAs
95 CPUID_AESNI_BIT = (1U << 16),
96 CPUID_CLMUL_BIT = (1U << 17),
97 CPUID_RDRAND_BIT = (1U << 18),
98 CPUID_RDSEED_BIT = (1U << 19),
99 CPUID_SHA_BIT = (1U << 20),
100 CPUID_AVX512_AES_BIT = (1U << 21),
101 CPUID_AVX512_CLMUL_BIT = (1U << 22),
102#endif
103
104#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
105 CPUID_ALTIVEC_BIT = (1U << 0),
106 CPUID_POWER_CRYPTO_BIT = (1U << 1),
107 CPUID_DARN_BIT = (1U << 2),
108#endif
109
110#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
111 CPUID_ARM_NEON_BIT = (1U << 0),
112 CPUID_ARM_SVE_BIT = (1U << 1),
113 CPUID_ARM_AES_BIT = (1U << 16),
114 CPUID_ARM_PMULL_BIT = (1U << 17),
115 CPUID_ARM_SHA1_BIT = (1U << 18),
116 CPUID_ARM_SHA2_BIT = (1U << 19),
117 CPUID_ARM_SHA3_BIT = (1U << 20),
118 CPUID_ARM_SHA2_512_BIT = (1U << 21),
119 CPUID_ARM_SM3_BIT = (1U << 22),
120 CPUID_ARM_SM4_BIT = (1U << 23),
121#endif
122
123 CPUID_IS_BIG_ENDIAN_BIT = (1U << 30),
124 CPUID_INITIALIZED_BIT = (1U << 31)
125 };
126
127#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
128 /**
129 * Check if the processor supports AltiVec/VMX
130 */
131 static bool has_altivec() { return has_cpuid_bit(CPUID_ALTIVEC_BIT); }
132
133 /**
134 * Check if the processor supports POWER8 crypto extensions
135 */
136 static bool has_power_crypto() { return has_altivec() && has_cpuid_bit(CPUID_POWER_CRYPTO_BIT); }
137
138 /**
139 * Check if the processor supports POWER9 DARN RNG
140 */
141 static bool has_darn_rng() { return has_cpuid_bit(CPUID_DARN_BIT); }
142
143#endif
144
145#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
146 /**
147 * Check if the processor supports NEON SIMD
148 */
149 static bool has_neon() { return has_cpuid_bit(CPUID_ARM_NEON_BIT); }
150
151 /**
152 * Check if the processor supports ARMv8 SVE
153 */
154 static bool has_arm_sve() { return has_cpuid_bit(CPUID_ARM_SVE_BIT); }
155
156 /**
157 * Check if the processor supports ARMv8 SHA1
158 */
159 static bool has_arm_sha1() { return has_neon() && has_cpuid_bit(CPUID_ARM_SHA1_BIT); }
160
161 /**
162 * Check if the processor supports ARMv8 SHA2
163 */
164 static bool has_arm_sha2() { return has_neon() && has_cpuid_bit(CPUID_ARM_SHA2_BIT); }
165
166 /**
167 * Check if the processor supports ARMv8 AES
168 */
169 static bool has_arm_aes() { return has_neon() && has_cpuid_bit(CPUID_ARM_AES_BIT); }
170
171 /**
172 * Check if the processor supports ARMv8 PMULL
173 */
174 static bool has_arm_pmull() { return has_neon() && has_cpuid_bit(CPUID_ARM_PMULL_BIT); }
175
176 /**
177 * Check if the processor supports ARMv8 SHA-512
178 */
179 static bool has_arm_sha2_512() { return has_neon() && has_cpuid_bit(CPUID_ARM_SHA2_512_BIT); }
180
181 /**
182 * Check if the processor supports ARMv8 SHA-3
183 */
184 static bool has_arm_sha3() { return has_neon() && has_cpuid_bit(CPUID_ARM_SHA3_BIT); }
185
186 /**
187 * Check if the processor supports ARMv8 SM3
188 */
189 static bool has_arm_sm3() { return has_neon() && has_cpuid_bit(CPUID_ARM_SM3_BIT); }
190
191 /**
192 * Check if the processor supports ARMv8 SM4
193 */
194 static bool has_arm_sm4() { return has_neon() && has_cpuid_bit(CPUID_ARM_SM4_BIT); }
195
196#endif
197
198#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
199
200 /**
201 * Check if the processor supports RDTSC
202 */
203 static bool has_rdtsc() { return has_cpuid_bit(CPUID_RDTSC_BIT); }
204
205 /**
206 * Check if the processor supports SSE2
207 */
208 static bool has_sse2() { return has_cpuid_bit(CPUID_SSE2_BIT); }
209
210 /**
211 * Check if the processor supports SSSE3
212 */
213 static bool has_ssse3() { return has_sse2() && has_cpuid_bit(CPUID_SSSE3_BIT); }
214
215 /**
216 * Check if the processor supports AVX2
217 */
218 static bool has_avx2() { return has_cpuid_bit(CPUID_AVX2_BIT); }
219
220 /**
221 * Check if the processor supports our AVX-512 minimum profile
222 *
223 * Namely AVX-512 F, DQ, BW, VL, IFMA, VBMI, VBMI2, BITALG
224 */
225 static bool has_avx512() { return has_cpuid_bit(CPUID_AVX512_BIT); }
226
227 /**
228 * Check if the processor supports AVX-512 AES (VAES)
229 */
230 static bool has_avx512_aes() { return has_avx512() && has_cpuid_bit(CPUID_AVX512_AES_BIT); }
231
232 /**
233 * Check if the processor supports AVX-512 VPCLMULQDQ
234 */
235 static bool has_avx512_clmul() { return has_avx512() && has_cpuid_bit(CPUID_AVX512_CLMUL_BIT); }
236
237 /**
238 * Check if the processor supports BMI2 (and BMI1)
239 */
240 static bool has_bmi2() { return has_cpuid_bit(CPUID_BMI_BIT); }
241
242 /**
243 * Check if the processor supports AES-NI
244 */
245 static bool has_aes_ni() { return has_ssse3() && has_cpuid_bit(CPUID_AESNI_BIT); }
246
247 /**
248 * Check if the processor supports CLMUL
249 */
250 static bool has_clmul() { return has_ssse3() && has_cpuid_bit(CPUID_CLMUL_BIT); }
251
252 /**
253 * Check if the processor supports Intel SHA extension
254 */
255 static bool has_intel_sha() { return has_sse2() && has_cpuid_bit(CPUID_SHA_BIT); }
256
257 /**
258 * Check if the processor supports ADX extension
259 */
260 static bool has_adx() { return has_cpuid_bit(CPUID_ADX_BIT); }
261
262 /**
263 * Check if the processor supports RDRAND
264 */
265 static bool has_rdrand() { return has_cpuid_bit(CPUID_RDRAND_BIT); }
266
267 /**
268 * Check if the processor supports RDSEED
269 */
270 static bool has_rdseed() { return has_cpuid_bit(CPUID_RDSEED_BIT); }
271#endif
272
273 /**
274 * Check if the processor supports byte-level vector permutes
275 * (SSSE3, NEON, Altivec)
276 */
277 static bool has_vperm() {
278#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
279 return has_ssse3();
280#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
281 return has_neon();
282#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
283 return has_altivec();
284#else
285 return false;
286#endif
287 }
288
289 /**
290 * Check if the processor supports hardware AES instructions
291 */
292 static bool has_hw_aes() {
293#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
294 return has_aes_ni();
295#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
296 return has_arm_aes();
297#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
298 return has_power_crypto();
299#else
300 return false;
301#endif
302 }
303
304 /**
305 * Check if the processor supports carryless multiply
306 * (CLMUL, PMULL)
307 */
309#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
310 return has_clmul();
311#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
312 return has_arm_pmull();
313#elif defined(BOTAN_TARGET_ARCH_IS_PPC64)
314 return has_power_crypto();
315#else
316 return false;
317#endif
318 }
319
320 /*
321 * Clear a CPUID bit
322 * Call CPUID::initialize to reset
323 *
324 * This is only exposed for testing, don't use unless you know
325 * what you are doing.
326 */
327 static void clear_cpuid_bit(CPUID_bits bit) { state().clear_cpuid_bit(static_cast<uint32_t>(bit)); }
328
329 /*
330 * Don't call this function, use CPUID::has_xxx above
331 * It is only exposed for the tests.
332 */
333 static bool has_cpuid_bit(CPUID_bits elem) {
334 const uint32_t elem32 = static_cast<uint32_t>(elem);
335 return state().has_bit(elem32);
336 }
337
338 static std::vector<CPUID::CPUID_bits> bit_from_string(std::string_view tok);
339
340 private:
341 struct CPUID_Data {
342 public:
343 CPUID_Data();
344
345 CPUID_Data(const CPUID_Data& other) = default;
346 CPUID_Data& operator=(const CPUID_Data& other) = default;
347
348 void clear_cpuid_bit(uint32_t bit) { m_processor_features &= ~bit; }
349
350 bool has_bit(uint32_t bit) const { return (m_processor_features & bit) == bit; }
351
352 private:
353#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
354 defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
355
356 static uint32_t detect_cpu_features();
357
358#endif
359 uint32_t m_processor_features;
360 };
361
362 static CPUID_Data& state() {
363 static CPUID::CPUID_Data g_cpuid;
364 return g_cpuid;
365 }
366};
367
368} // namespace Botan
369
370#endif
static bool has_vperm()
Definition cpuid.h:277
static bool is_little_endian()
Definition cpuid.h:59
static bool is_big_endian()
Definition cpuid.h:69
static bool has_cpuid_bit(CPUID_bits elem)
Definition cpuid.h:333
static bool has_carryless_multiply()
Definition cpuid.h:308
static void clear_cpuid_bit(CPUID_bits bit)
Definition cpuid.h:327
static bool has_hw_aes()
Definition cpuid.h:292
int(* final)(unsigned char *, CTX *)
#define BOTAN_TEST_API
Definition compiler.h:51