Botan 2.13.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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
18 namespace 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 // Misc useful instructions
108 CPUID_RDTSC_BIT = (1ULL << 10),
109 CPUID_BMI2_BIT = (1ULL << 11),
110 CPUID_ADX_BIT = (1ULL << 12),
111 CPUID_BMI1_BIT = (1ULL << 13),
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 #endif
120
121 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
122 CPUID_ALTIVEC_BIT = (1ULL << 0),
123 CPUID_POWER_CRYPTO_BIT = (1ULL << 1),
124 CPUID_DARN_BIT = (1ULL << 2),
125 #endif
126
127 #if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
128 CPUID_ARM_NEON_BIT = (1ULL << 0),
129 CPUID_ARM_SVE_BIT = (1ULL << 1),
130 CPUID_ARM_AES_BIT = (1ULL << 16),
131 CPUID_ARM_PMULL_BIT = (1ULL << 17),
132 CPUID_ARM_SHA1_BIT = (1ULL << 18),
133 CPUID_ARM_SHA2_BIT = (1ULL << 19),
134 CPUID_ARM_SHA3_BIT = (1ULL << 20),
135 CPUID_ARM_SHA2_512_BIT = (1ULL << 21),
136 CPUID_ARM_SM3_BIT = (1ULL << 22),
137 CPUID_ARM_SM4_BIT = (1ULL << 23),
138 #endif
139
140 CPUID_INITIALIZED_BIT = (1ULL << 63)
141 };
142
143 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
144 /**
145 * Check if the processor supports AltiVec/VMX
146 */
147 static bool has_altivec()
148 { return has_cpuid_bit(CPUID_ALTIVEC_BIT); }
149
150 /**
151 * Check if the processor supports POWER8 crypto extensions
152 */
153 static bool has_power_crypto()
154 { return has_cpuid_bit(CPUID_POWER_CRYPTO_BIT); }
155
156 /**
157 * Check if the processor supports POWER9 DARN RNG
158 */
159 static bool has_darn_rng()
160 { return has_cpuid_bit(CPUID_DARN_BIT); }
161
162 #endif
163
164 #if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
165 /**
166 * Check if the processor supports NEON SIMD
167 */
168 static bool has_neon()
169 { return has_cpuid_bit(CPUID_ARM_NEON_BIT); }
170
171 /**
172 * Check if the processor supports ARMv8 SVE
173 */
174 static bool has_arm_sve()
175 { return has_cpuid_bit(CPUID_ARM_SVE_BIT); }
176
177 /**
178 * Check if the processor supports ARMv8 SHA1
179 */
180 static bool has_arm_sha1()
181 { return has_cpuid_bit(CPUID_ARM_SHA1_BIT); }
182
183 /**
184 * Check if the processor supports ARMv8 SHA2
185 */
186 static bool has_arm_sha2()
187 { 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()
193 { return has_cpuid_bit(CPUID_ARM_AES_BIT); }
194
195 /**
196 * Check if the processor supports ARMv8 PMULL
197 */
198 static bool has_arm_pmull()
199 { return has_cpuid_bit(CPUID_ARM_PMULL_BIT); }
200
201 /**
202 * Check if the processor supports ARMv8 SHA-512
203 */
204 static bool has_arm_sha2_512()
205 { return has_cpuid_bit(CPUID_ARM_SHA2_512_BIT); }
206
207 /**
208 * Check if the processor supports ARMv8 SHA-3
209 */
210 static bool has_arm_sha3()
211 { return has_cpuid_bit(CPUID_ARM_SHA3_BIT); }
212
213 /**
214 * Check if the processor supports ARMv8 SM3
215 */
216 static bool has_arm_sm3()
217 { return has_cpuid_bit(CPUID_ARM_SM3_BIT); }
218
219 /**
220 * Check if the processor supports ARMv8 SM4
221 */
222 static bool has_arm_sm4()
223 { return has_cpuid_bit(CPUID_ARM_SM4_BIT); }
224
225 #endif
226
227 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
228
229 /**
230 * Check if the processor supports RDTSC
231 */
232 static bool has_rdtsc()
233 { return has_cpuid_bit(CPUID_RDTSC_BIT); }
234
235 /**
236 * Check if the processor supports SSE2
237 */
238 static bool has_sse2()
239 { return has_cpuid_bit(CPUID_SSE2_BIT); }
240
241 /**
242 * Check if the processor supports SSSE3
243 */
244 static bool has_ssse3()
245 { return has_cpuid_bit(CPUID_SSSE3_BIT); }
246
247 /**
248 * Check if the processor supports SSE4.1
249 */
250 static bool has_sse41()
251 { return has_cpuid_bit(CPUID_SSE41_BIT); }
252
253 /**
254 * Check if the processor supports SSE4.2
255 */
256 static bool has_sse42()
257 { return has_cpuid_bit(CPUID_SSE42_BIT); }
258
259 /**
260 * Check if the processor supports AVX2
261 */
262 static bool has_avx2()
263 { return has_cpuid_bit(CPUID_AVX2_BIT); }
264
265 /**
266 * Check if the processor supports AVX-512F
267 */
268 static bool has_avx512f()
269 { return has_cpuid_bit(CPUID_AVX512F_BIT); }
270
271 /**
272 * Check if the processor supports BMI1
273 */
274 static bool has_bmi1()
275 { return has_cpuid_bit(CPUID_BMI1_BIT); }
276
277 /**
278 * Check if the processor supports BMI2
279 */
280 static bool has_bmi2()
281 { return has_cpuid_bit(CPUID_BMI2_BIT); }
282
283 /**
284 * Check if the processor supports AES-NI
285 */
286 static bool has_aes_ni()
287 { return has_cpuid_bit(CPUID_AESNI_BIT); }
288
289 /**
290 * Check if the processor supports CLMUL
291 */
292 static bool has_clmul()
293 { 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()
299 { return has_cpuid_bit(CPUID_SHA_BIT); }
300
301 /**
302 * Check if the processor supports ADX extension
303 */
304 static bool has_adx()
305 { return has_cpuid_bit(CPUID_ADX_BIT); }
306
307 /**
308 * Check if the processor supports RDRAND
309 */
310 static bool has_rdrand()
311 { return has_cpuid_bit(CPUID_RDRAND_BIT); }
312
313 /**
314 * Check if the processor supports RDSEED
315 */
316 static bool has_rdseed()
317 { return has_cpuid_bit(CPUID_RDSEED_BIT); }
318 #endif
319
320 /**
321 * Check if the processor supports byte-level vector permutes
322 * (SSSE3, NEON, Altivec)
323 */
324 static bool has_vperm()
325 {
326 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
327 return has_ssse3();
328 #elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
329 return has_neon();
330 #elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
331 return has_altivec();
332 #else
333 return false;
334 #endif
335 }
336
337 /**
338 * Check if the processor supports carryless multiply
339 * (CLMUL, PMULL)
340 */
341 static bool has_carryless_multiply()
342 {
343 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
344 return has_clmul();
345 #elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
346 return has_arm_pmull();
347 #else
348 return false;
349 #endif
350 }
351
352 /*
353 * Clear a CPUID bit
354 * Call CPUID::initialize to reset
355 *
356 * This is only exposed for testing, don't use unless you know
357 * what you are doing.
358 */
359 static void clear_cpuid_bit(CPUID_bits bit)
360 {
361 state().clear_cpuid_bit(static_cast<uint64_t>(bit));
362 }
363
364 /*
365 * Don't call this function, use CPUID::has_xxx above
366 * It is only exposed for the tests.
367 */
368 static bool has_cpuid_bit(CPUID_bits elem)
369 {
370 const uint64_t elem64 = static_cast<uint64_t>(elem);
371 return state().has_bit(elem64);
372 }
373
374 static std::vector<CPUID::CPUID_bits> bit_from_string(const std::string& tok);
375 private:
376 enum class Endian_Status : uint32_t {
377 Unknown = 0x00000000,
378 Big = 0x01234567,
379 Little = 0x67452301,
380 };
381
382 struct CPUID_Data
383 {
384 public:
385 CPUID_Data();
386
387 CPUID_Data(const CPUID_Data& other) = default;
388 CPUID_Data& operator=(const CPUID_Data& other) = default;
389
390 void clear_cpuid_bit(uint64_t bit)
391 {
392 m_processor_features &= ~bit;
393 }
394
395 bool has_bit(uint64_t bit) const
396 {
397 return (m_processor_features & bit) == bit;
398 }
399
400 uint64_t processor_features() const { return m_processor_features; }
401 Endian_Status endian_status() const { return m_endian_status; }
402 size_t cache_line_size() const { return m_cache_line_size; }
403
404 private:
405 static Endian_Status runtime_check_endian();
406
407 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \
408 defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
409 defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
410
411 static uint64_t detect_cpu_features(size_t* cache_line_size);
412
413 #endif
414 uint64_t m_processor_features;
415 size_t m_cache_line_size;
416 Endian_Status m_endian_status;
417 };
418
419 static CPUID_Data& state()
420 {
421 static CPUID::CPUID_Data g_cpuid;
422 return g_cpuid;
423 }
424 };
425
426 }
427
428 #endif
Botan::CPUID
Definition: cpuid.h:38
Botan::CPUID::cache_line_size
static size_t cache_line_size()
Definition: cpuid.h:68
final
int(* final)(unsigned char *, CTX *)
Definition: commoncrypto_hash.cpp:28
BOTAN_PUBLIC_API
#define BOTAN_PUBLIC_API(maj, min)
Definition: compiler.h:31
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
Botan::CPUID::has_carryless_multiply
static bool has_carryless_multiply()
Definition: cpuid.h:341
Botan::CPUID::is_little_endian
static bool is_little_endian()
Definition: cpuid.h:73
Botan::ErrorType::Unknown
Botan
Definition: alg_id.cpp:13
Botan::CPUID::CPUID_bits
CPUID_bits
Definition: cpuid.h:95
Botan::CPUID::has_vperm
static bool has_vperm()
Definition: cpuid.h:324
Botan::CPUID::clear_cpuid_bit
static void clear_cpuid_bit(CPUID_bits bit)
Definition: cpuid.h:359
Botan::CPUID::has_cpuid_bit
static bool has_cpuid_bit(CPUID_bits elem)
Definition: cpuid.h:368
Botan::CPUID::is_big_endian
static bool is_big_endian()
Definition: cpuid.h:84
BOTAN_FUTURE_INTERNAL_HEADER
#define BOTAN_FUTURE_INTERNAL_HEADER(hdr)
Definition: compiler.h:139