Botan  2.8.0
Crypto and TLS for C++11
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 namespace 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 Darwin
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  static bool has_simd_32();
45 
46  /**
47  * Deprecated equivalent to
48  * o << "CPUID flags: " << CPUID::to_string() << "\n";
49  */
50  BOTAN_DEPRECATED("Use CPUID::to_string")
51  static void print(std::ostream& o);
52 
53  /**
54  * Return a possibly empty string containing list of known CPU
55  * extensions. Each name will be seperated by a space, and the ordering
56  * will be arbitrary. This list only contains values that are useful to
57  * Botan (for example FMA instructions are not checked).
58  *
59  * Example outputs "sse2 ssse3 rdtsc", "neon arm_aes", "altivec"
60  */
61  static std::string to_string();
62 
63  /**
64  * Return a best guess of the cache line size
65  */
66  static size_t cache_line_size()
67  {
68  if(g_processor_features == 0)
69  {
70  initialize();
71  }
72  return g_cache_line_size;
73  }
74 
75  static bool is_little_endian()
76  {
77  return endian_status() == ENDIAN_LITTLE;
78  }
79 
80  static bool is_big_endian()
81  {
82  return endian_status() == ENDIAN_BIG;
83  }
84 
85  enum CPUID_bits : uint64_t {
86 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
87  // These values have no relation to cpuid bitfields
88 
89  // SIMD instruction sets
90  CPUID_SSE2_BIT = (1ULL << 0),
91  CPUID_SSSE3_BIT = (1ULL << 1),
92  CPUID_SSE41_BIT = (1ULL << 2),
93  CPUID_SSE42_BIT = (1ULL << 3),
94  CPUID_AVX2_BIT = (1ULL << 4),
95  CPUID_AVX512F_BIT = (1ULL << 5),
96 
97  // Misc useful instructions
98  CPUID_RDTSC_BIT = (1ULL << 10),
99  CPUID_BMI2_BIT = (1ULL << 11),
100  CPUID_ADX_BIT = (1ULL << 12),
101  CPUID_BMI1_BIT = (1ULL << 13),
102 
103  // Crypto-specific ISAs
104  CPUID_AESNI_BIT = (1ULL << 16),
105  CPUID_CLMUL_BIT = (1ULL << 17),
106  CPUID_RDRAND_BIT = (1ULL << 18),
107  CPUID_RDSEED_BIT = (1ULL << 19),
108  CPUID_SHA_BIT = (1ULL << 20),
109 #endif
110 
111 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
112  CPUID_ALTIVEC_BIT = (1ULL << 0),
113  CPUID_PPC_CRYPTO_BIT = (1ULL << 1),
114 #endif
115 
116 #if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
117  CPUID_ARM_NEON_BIT = (1ULL << 0),
118  CPUID_ARM_SVE_BIT = (1ULL << 1),
119  CPUID_ARM_AES_BIT = (1ULL << 16),
120  CPUID_ARM_PMULL_BIT = (1ULL << 17),
121  CPUID_ARM_SHA1_BIT = (1ULL << 18),
122  CPUID_ARM_SHA2_BIT = (1ULL << 19),
123  CPUID_ARM_SHA3_BIT = (1ULL << 20),
124  CPUID_ARM_SHA2_512_BIT = (1ULL << 21),
125  CPUID_ARM_SM3_BIT = (1ULL << 22),
126  CPUID_ARM_SM4_BIT = (1ULL << 23),
127 #endif
128 
129  CPUID_INITIALIZED_BIT = (1ULL << 63)
130  };
131 
132 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
133  /**
134  * Check if the processor supports AltiVec/VMX
135  */
136  static bool has_altivec()
137  { return has_cpuid_bit(CPUID_ALTIVEC_BIT); }
138 
139  /**
140  * Check if the processor supports POWER8 crypto extensions
141  */
142  static bool has_ppc_crypto()
143  { return has_cpuid_bit(CPUID_PPC_CRYPTO_BIT); }
144 
145 #endif
146 
147 #if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
148  /**
149  * Check if the processor supports NEON SIMD
150  */
151  static bool has_neon()
152  { return has_cpuid_bit(CPUID_ARM_NEON_BIT); }
153 
154  /**
155  * Check if the processor supports ARMv8 SVE
156  */
157  static bool has_arm_sve()
158  { return has_cpuid_bit(CPUID_ARM_SVE_BIT); }
159 
160  /**
161  * Check if the processor supports ARMv8 SHA1
162  */
163  static bool has_arm_sha1()
164  { return has_cpuid_bit(CPUID_ARM_SHA1_BIT); }
165 
166  /**
167  * Check if the processor supports ARMv8 SHA2
168  */
169  static bool has_arm_sha2()
170  { return has_cpuid_bit(CPUID_ARM_SHA2_BIT); }
171 
172  /**
173  * Check if the processor supports ARMv8 AES
174  */
175  static bool has_arm_aes()
176  { return has_cpuid_bit(CPUID_ARM_AES_BIT); }
177 
178  /**
179  * Check if the processor supports ARMv8 PMULL
180  */
181  static bool has_arm_pmull()
182  { return has_cpuid_bit(CPUID_ARM_PMULL_BIT); }
183 
184  /**
185  * Check if the processor supports ARMv8 SHA-512
186  */
187  static bool has_arm_sha2_512()
188  { return has_cpuid_bit(CPUID_ARM_SHA2_512_BIT); }
189 
190  /**
191  * Check if the processor supports ARMv8 SHA-3
192  */
193  static bool has_arm_sha3()
194  { return has_cpuid_bit(CPUID_ARM_SHA3_BIT); }
195 
196  /**
197  * Check if the processor supports ARMv8 SM3
198  */
199  static bool has_arm_sm3()
200  { return has_cpuid_bit(CPUID_ARM_SM3_BIT); }
201 
202  /**
203  * Check if the processor supports ARMv8 SM4
204  */
205  static bool has_arm_sm4()
206  { return has_cpuid_bit(CPUID_ARM_SM4_BIT); }
207 
208 #endif
209 
210 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
211 
212  /**
213  * Check if the processor supports RDTSC
214  */
215  static bool has_rdtsc()
216  { return has_cpuid_bit(CPUID_RDTSC_BIT); }
217 
218  /**
219  * Check if the processor supports SSE2
220  */
221  static bool has_sse2()
222  { return has_cpuid_bit(CPUID_SSE2_BIT); }
223 
224  /**
225  * Check if the processor supports SSSE3
226  */
227  static bool has_ssse3()
228  { return has_cpuid_bit(CPUID_SSSE3_BIT); }
229 
230  /**
231  * Check if the processor supports SSE4.1
232  */
233  static bool has_sse41()
234  { return has_cpuid_bit(CPUID_SSE41_BIT); }
235 
236  /**
237  * Check if the processor supports SSE4.2
238  */
239  static bool has_sse42()
240  { return has_cpuid_bit(CPUID_SSE42_BIT); }
241 
242  /**
243  * Check if the processor supports AVX2
244  */
245  static bool has_avx2()
246  { return has_cpuid_bit(CPUID_AVX2_BIT); }
247 
248  /**
249  * Check if the processor supports AVX-512F
250  */
251  static bool has_avx512f()
252  { return has_cpuid_bit(CPUID_AVX512F_BIT); }
253 
254  /**
255  * Check if the processor supports BMI1
256  */
257  static bool has_bmi1()
258  { return has_cpuid_bit(CPUID_BMI1_BIT); }
259 
260  /**
261  * Check if the processor supports BMI2
262  */
263  static bool has_bmi2()
264  { return has_cpuid_bit(CPUID_BMI2_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  * Clear a CPUID bit
305  * Call CPUID::initialize to reset
306  *
307  * This is only exposed for testing, don't use unless you know
308  * what you are doing.
309  */
310  static void clear_cpuid_bit(CPUID_bits bit)
311  {
312  const uint64_t mask = ~(static_cast<uint64_t>(bit));
313  g_processor_features &= mask;
314  }
315 
316  /*
317  * Don't call this function, use CPUID::has_xxx above
318  * It is only exposed for the tests.
319  */
320  static bool has_cpuid_bit(CPUID_bits elem)
321  {
322  if(g_processor_features == 0)
323  initialize();
324 
325  const uint64_t elem64 = static_cast<uint64_t>(elem);
326  return ((g_processor_features & elem64) == elem64);
327  }
328 
329  static std::vector<CPUID::CPUID_bits> bit_from_string(const std::string& tok);
330  private:
331  enum Endian_status : uint32_t {
332  ENDIAN_UNKNOWN = 0x00000000,
333  ENDIAN_BIG = 0x01234567,
334  ENDIAN_LITTLE = 0x67452301,
335  };
336 
337 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \
338  defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
339  defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
340 
341  static uint64_t detect_cpu_features(size_t* cache_line_size);
342 
343 #endif
344 
345  static Endian_status runtime_check_endian();
346 
347  static Endian_status endian_status()
348  {
349  if(g_endian_status == ENDIAN_UNKNOWN)
350  {
351  g_endian_status = runtime_check_endian();
352  }
353  return g_endian_status;
354  }
355 
356  static uint64_t g_processor_features;
357  static size_t g_cache_line_size;
358  static Endian_status g_endian_status;
359  };
360 
361 }
362 
363 #endif
static size_t cache_line_size()
Definition: cpuid.h:66
int(* final)(unsigned char *, CTX *)
#define BOTAN_PUBLIC_API(maj, min)
Definition: compiler.h:27
static bool is_little_endian()
Definition: cpuid.h:75
Definition: alg_id.cpp:13
std::string to_string(const secure_vector< uint8_t > &bytes)
Definition: stl_util.h:25
static void clear_cpuid_bit(CPUID_bits bit)
Definition: cpuid.h:310
static bool has_cpuid_bit(CPUID_bits elem)
Definition: cpuid.h:320
static bool is_big_endian()
Definition: cpuid.h:80