Botan  2.11.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 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  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  return state().cache_line_size();
69  }
70 
71  static bool is_little_endian()
72  {
73  return state().endian_status() == Endian_Status::Little;
74  }
75 
76  static bool is_big_endian()
77  {
78  return state().endian_status() == Endian_Status::Big;
79  }
80 
81  enum CPUID_bits : uint64_t {
82 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
83  // These values have no relation to cpuid bitfields
84 
85  // SIMD instruction sets
86  CPUID_SSE2_BIT = (1ULL << 0),
87  CPUID_SSSE3_BIT = (1ULL << 1),
88  CPUID_SSE41_BIT = (1ULL << 2),
89  CPUID_SSE42_BIT = (1ULL << 3),
90  CPUID_AVX2_BIT = (1ULL << 4),
91  CPUID_AVX512F_BIT = (1ULL << 5),
92 
93  // Misc useful instructions
94  CPUID_RDTSC_BIT = (1ULL << 10),
95  CPUID_BMI2_BIT = (1ULL << 11),
96  CPUID_ADX_BIT = (1ULL << 12),
97  CPUID_BMI1_BIT = (1ULL << 13),
98 
99  // Crypto-specific ISAs
100  CPUID_AESNI_BIT = (1ULL << 16),
101  CPUID_CLMUL_BIT = (1ULL << 17),
102  CPUID_RDRAND_BIT = (1ULL << 18),
103  CPUID_RDSEED_BIT = (1ULL << 19),
104  CPUID_SHA_BIT = (1ULL << 20),
105 #endif
106 
107 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
108  CPUID_ALTIVEC_BIT = (1ULL << 0),
109  CPUID_PPC_CRYPTO_BIT = (1ULL << 1),
110 #endif
111 
112 #if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
113  CPUID_ARM_NEON_BIT = (1ULL << 0),
114  CPUID_ARM_SVE_BIT = (1ULL << 1),
115  CPUID_ARM_AES_BIT = (1ULL << 16),
116  CPUID_ARM_PMULL_BIT = (1ULL << 17),
117  CPUID_ARM_SHA1_BIT = (1ULL << 18),
118  CPUID_ARM_SHA2_BIT = (1ULL << 19),
119  CPUID_ARM_SHA3_BIT = (1ULL << 20),
120  CPUID_ARM_SHA2_512_BIT = (1ULL << 21),
121  CPUID_ARM_SM3_BIT = (1ULL << 22),
122  CPUID_ARM_SM4_BIT = (1ULL << 23),
123 #endif
124 
125  CPUID_INITIALIZED_BIT = (1ULL << 63)
126  };
127 
128 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
129  /**
130  * Check if the processor supports AltiVec/VMX
131  */
132  static bool has_altivec()
133  { return has_cpuid_bit(CPUID_ALTIVEC_BIT); }
134 
135  /**
136  * Check if the processor supports POWER8 crypto extensions
137  */
138  static bool has_ppc_crypto()
139  { return has_cpuid_bit(CPUID_PPC_CRYPTO_BIT); }
140 
141 #endif
142 
143 #if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
144  /**
145  * Check if the processor supports NEON SIMD
146  */
147  static bool has_neon()
148  { return has_cpuid_bit(CPUID_ARM_NEON_BIT); }
149 
150  /**
151  * Check if the processor supports ARMv8 SVE
152  */
153  static bool has_arm_sve()
154  { 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()
160  { return has_cpuid_bit(CPUID_ARM_SHA1_BIT); }
161 
162  /**
163  * Check if the processor supports ARMv8 SHA2
164  */
165  static bool has_arm_sha2()
166  { return has_cpuid_bit(CPUID_ARM_SHA2_BIT); }
167 
168  /**
169  * Check if the processor supports ARMv8 AES
170  */
171  static bool has_arm_aes()
172  { return has_cpuid_bit(CPUID_ARM_AES_BIT); }
173 
174  /**
175  * Check if the processor supports ARMv8 PMULL
176  */
177  static bool has_arm_pmull()
178  { return has_cpuid_bit(CPUID_ARM_PMULL_BIT); }
179 
180  /**
181  * Check if the processor supports ARMv8 SHA-512
182  */
183  static bool has_arm_sha2_512()
184  { return has_cpuid_bit(CPUID_ARM_SHA2_512_BIT); }
185 
186  /**
187  * Check if the processor supports ARMv8 SHA-3
188  */
189  static bool has_arm_sha3()
190  { return has_cpuid_bit(CPUID_ARM_SHA3_BIT); }
191 
192  /**
193  * Check if the processor supports ARMv8 SM3
194  */
195  static bool has_arm_sm3()
196  { return has_cpuid_bit(CPUID_ARM_SM3_BIT); }
197 
198  /**
199  * Check if the processor supports ARMv8 SM4
200  */
201  static bool has_arm_sm4()
202  { return has_cpuid_bit(CPUID_ARM_SM4_BIT); }
203 
204 #endif
205 
206 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
207 
208  /**
209  * Check if the processor supports RDTSC
210  */
211  static bool has_rdtsc()
212  { return has_cpuid_bit(CPUID_RDTSC_BIT); }
213 
214  /**
215  * Check if the processor supports SSE2
216  */
217  static bool has_sse2()
218  { return has_cpuid_bit(CPUID_SSE2_BIT); }
219 
220  /**
221  * Check if the processor supports SSSE3
222  */
223  static bool has_ssse3()
224  { return has_cpuid_bit(CPUID_SSSE3_BIT); }
225 
226  /**
227  * Check if the processor supports SSE4.1
228  */
229  static bool has_sse41()
230  { return has_cpuid_bit(CPUID_SSE41_BIT); }
231 
232  /**
233  * Check if the processor supports SSE4.2
234  */
235  static bool has_sse42()
236  { return has_cpuid_bit(CPUID_SSE42_BIT); }
237 
238  /**
239  * Check if the processor supports AVX2
240  */
241  static bool has_avx2()
242  { return has_cpuid_bit(CPUID_AVX2_BIT); }
243 
244  /**
245  * Check if the processor supports AVX-512F
246  */
247  static bool has_avx512f()
248  { return has_cpuid_bit(CPUID_AVX512F_BIT); }
249 
250  /**
251  * Check if the processor supports BMI1
252  */
253  static bool has_bmi1()
254  { return has_cpuid_bit(CPUID_BMI1_BIT); }
255 
256  /**
257  * Check if the processor supports BMI2
258  */
259  static bool has_bmi2()
260  { return has_cpuid_bit(CPUID_BMI2_BIT); }
261 
262  /**
263  * Check if the processor supports AES-NI
264  */
265  static bool has_aes_ni()
266  { return has_cpuid_bit(CPUID_AESNI_BIT); }
267 
268  /**
269  * Check if the processor supports CLMUL
270  */
271  static bool has_clmul()
272  { return has_cpuid_bit(CPUID_CLMUL_BIT); }
273 
274  /**
275  * Check if the processor supports Intel SHA extension
276  */
277  static bool has_intel_sha()
278  { return has_cpuid_bit(CPUID_SHA_BIT); }
279 
280  /**
281  * Check if the processor supports ADX extension
282  */
283  static bool has_adx()
284  { return has_cpuid_bit(CPUID_ADX_BIT); }
285 
286  /**
287  * Check if the processor supports RDRAND
288  */
289  static bool has_rdrand()
290  { return has_cpuid_bit(CPUID_RDRAND_BIT); }
291 
292  /**
293  * Check if the processor supports RDSEED
294  */
295  static bool has_rdseed()
296  { return has_cpuid_bit(CPUID_RDSEED_BIT); }
297 #endif
298 
299  /*
300  * Clear a CPUID bit
301  * Call CPUID::initialize to reset
302  *
303  * This is only exposed for testing, don't use unless you know
304  * what you are doing.
305  */
306  static void clear_cpuid_bit(CPUID_bits bit)
307  {
308  state().clear_cpuid_bit(static_cast<uint64_t>(bit));
309  }
310 
311  /*
312  * Don't call this function, use CPUID::has_xxx above
313  * It is only exposed for the tests.
314  */
315  static bool has_cpuid_bit(CPUID_bits elem)
316  {
317  const uint64_t elem64 = static_cast<uint64_t>(elem);
318  return state().has_bit(elem64);
319  }
320 
321  static std::vector<CPUID::CPUID_bits> bit_from_string(const std::string& tok);
322  private:
323  enum class Endian_Status : uint32_t {
324  Unknown = 0x00000000,
325  Big = 0x01234567,
326  Little = 0x67452301,
327  };
328 
329  struct CPUID_Data
330  {
331  public:
332  CPUID_Data();
333 
334  CPUID_Data(const CPUID_Data& other) = default;
335  CPUID_Data& operator=(const CPUID_Data& other) = default;
336 
337  void clear_cpuid_bit(uint64_t bit)
338  {
339  m_processor_features &= ~bit;
340  }
341 
342  bool has_bit(uint64_t bit) const
343  {
344  return (m_processor_features & bit) == bit;
345  }
346 
347  uint64_t processor_features() const { return m_processor_features; }
348  Endian_Status endian_status() const { return m_endian_status; }
349  size_t cache_line_size() const { return m_cache_line_size; }
350 
351  private:
352  static Endian_Status runtime_check_endian();
353 
354 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \
355  defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
356  defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
357 
358  static uint64_t detect_cpu_features(size_t* cache_line_size);
359 
360 #endif
361  uint64_t m_processor_features;
362  size_t m_cache_line_size;
363  Endian_Status m_endian_status;
364  };
365 
366  static CPUID_Data& state();
367  };
368 
369 }
370 
371 #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:31
std::string to_string(ErrorType type)
Convert an ErrorType to string.
Definition: exceptn.cpp:11
static bool is_little_endian()
Definition: cpuid.h:71
Definition: alg_id.cpp:13
static void clear_cpuid_bit(CPUID_bits bit)
Definition: cpuid.h:306
static bool has_cpuid_bit(CPUID_bits elem)
Definition: cpuid.h:315
static bool is_big_endian()
Definition: cpuid.h:76