Botan  2.6.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 */
36 class BOTAN_PUBLIC_API(2,1) CPUID final
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 
102  // Crypto-specific ISAs
103  CPUID_AESNI_BIT = (1ULL << 16),
104  CPUID_CLMUL_BIT = (1ULL << 17),
105  CPUID_RDRAND_BIT = (1ULL << 18),
106  CPUID_RDSEED_BIT = (1ULL << 19),
107  CPUID_SHA_BIT = (1ULL << 20),
108 #endif
109 
110 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
111  CPUID_ALTIVEC_BIT = (1ULL << 0),
112  CPUID_PPC_CRYPTO_BIT = (1ULL << 1),
113 #endif
114 
115 #if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
116  CPUID_ARM_NEON_BIT = (1ULL << 0),
117  CPUID_ARM_AES_BIT = (1ULL << 16),
118  CPUID_ARM_PMULL_BIT = (1ULL << 17),
119  CPUID_ARM_SHA1_BIT = (1ULL << 18),
120  CPUID_ARM_SHA2_BIT = (1ULL << 19),
121 #endif
122 
123  CPUID_INITIALIZED_BIT = (1ULL << 63)
124  };
125 
126 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
127  /**
128  * Check if the processor supports AltiVec/VMX
129  */
130  static bool has_altivec()
131  { return has_cpuid_bit(CPUID_ALTIVEC_BIT); }
132 
133  /**
134  * Check if the processor supports POWER8 crypto extensions
135  */
136  static bool has_ppc_crypto()
137  { return has_cpuid_bit(CPUID_PPC_CRYPTO_BIT); }
138 
139 #endif
140 
141 #if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
142  /**
143  * Check if the processor supports NEON SIMD
144  */
145  static bool has_neon()
146  { return has_cpuid_bit(CPUID_ARM_NEON_BIT); }
147 
148  /**
149  * Check if the processor supports ARMv8 SHA1
150  */
151  static bool has_arm_sha1()
152  { return has_cpuid_bit(CPUID_ARM_SHA1_BIT); }
153 
154  /**
155  * Check if the processor supports ARMv8 SHA2
156  */
157  static bool has_arm_sha2()
158  { return has_cpuid_bit(CPUID_ARM_SHA2_BIT); }
159 
160  /**
161  * Check if the processor supports ARMv8 AES
162  */
163  static bool has_arm_aes()
164  { return has_cpuid_bit(CPUID_ARM_AES_BIT); }
165 
166  /**
167  * Check if the processor supports ARMv8 PMULL
168  */
169  static bool has_arm_pmull()
170  { return has_cpuid_bit(CPUID_ARM_PMULL_BIT); }
171 #endif
172 
173 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
174 
175  /**
176  * Check if the processor supports RDTSC
177  */
178  static bool has_rdtsc()
179  { return has_cpuid_bit(CPUID_RDTSC_BIT); }
180 
181  /**
182  * Check if the processor supports SSE2
183  */
184  static bool has_sse2()
185  { return has_cpuid_bit(CPUID_SSE2_BIT); }
186 
187  /**
188  * Check if the processor supports SSSE3
189  */
190  static bool has_ssse3()
191  { return has_cpuid_bit(CPUID_SSSE3_BIT); }
192 
193  /**
194  * Check if the processor supports SSE4.1
195  */
196  static bool has_sse41()
197  { return has_cpuid_bit(CPUID_SSE41_BIT); }
198 
199  /**
200  * Check if the processor supports SSE4.2
201  */
202  static bool has_sse42()
203  { return has_cpuid_bit(CPUID_SSE42_BIT); }
204 
205  /**
206  * Check if the processor supports AVX2
207  */
208  static bool has_avx2()
209  { return has_cpuid_bit(CPUID_AVX2_BIT); }
210 
211  /**
212  * Check if the processor supports AVX-512F
213  */
214  static bool has_avx512f()
215  { return has_cpuid_bit(CPUID_AVX512F_BIT); }
216 
217  /**
218  * Check if the processor supports BMI2
219  */
220  static bool has_bmi2()
221  { return has_cpuid_bit(CPUID_BMI2_BIT); }
222 
223  /**
224  * Check if the processor supports AES-NI
225  */
226  static bool has_aes_ni()
227  { return has_cpuid_bit(CPUID_AESNI_BIT); }
228 
229  /**
230  * Check if the processor supports CLMUL
231  */
232  static bool has_clmul()
233  { return has_cpuid_bit(CPUID_CLMUL_BIT); }
234 
235  /**
236  * Check if the processor supports Intel SHA extension
237  */
238  static bool has_intel_sha()
239  { return has_cpuid_bit(CPUID_SHA_BIT); }
240 
241  /**
242  * Check if the processor supports ADX extension
243  */
244  static bool has_adx()
245  { return has_cpuid_bit(CPUID_ADX_BIT); }
246 
247  /**
248  * Check if the processor supports RDRAND
249  */
250  static bool has_rdrand()
251  { return has_cpuid_bit(CPUID_RDRAND_BIT); }
252 
253  /**
254  * Check if the processor supports RDSEED
255  */
256  static bool has_rdseed()
257  { return has_cpuid_bit(CPUID_RDSEED_BIT); }
258 #endif
259 
260  /*
261  * Clear a CPUID bit
262  * Call CPUID::initialize to reset
263  *
264  * This is only exposed for testing, don't use unless you know
265  * what you are doing.
266  */
267  static void clear_cpuid_bit(CPUID_bits bit)
268  {
269  const uint64_t mask = ~(static_cast<uint64_t>(bit));
270  g_processor_features &= mask;
271  }
272 
273  /*
274  * Don't call this function, use CPUID::has_xxx above
275  * It is only exposed for the tests.
276  */
277  static bool has_cpuid_bit(CPUID_bits elem)
278  {
279  if(g_processor_features == 0)
280  initialize();
281 
282  const uint64_t elem64 = static_cast<uint64_t>(elem);
283  return ((g_processor_features & elem64) == elem64);
284  }
285 
286  static std::vector<CPUID::CPUID_bits> bit_from_string(const std::string& tok);
287  private:
288  enum Endian_status : uint32_t {
289  ENDIAN_UNKNOWN = 0x00000000,
290  ENDIAN_BIG = 0x01234567,
291  ENDIAN_LITTLE = 0x67452301,
292  };
293 
294 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \
295  defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
296  defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
297 
298  static uint64_t detect_cpu_features(size_t* cache_line_size);
299 
300 #endif
301 
302  static Endian_status runtime_check_endian();
303 
304  static Endian_status endian_status()
305  {
306  if(g_endian_status == ENDIAN_UNKNOWN)
307  {
308  g_endian_status = runtime_check_endian();
309  }
310  return g_endian_status;
311  }
312 
313  static uint64_t g_processor_features;
314  static size_t g_cache_line_size;
315  static Endian_status g_endian_status;
316  };
317 
318 }
319 
320 #endif
static size_t cache_line_size()
Definition: cpuid.h:66
#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:267
static bool has_cpuid_bit(CPUID_bits elem)
Definition: cpuid.h:277
static bool is_big_endian()
Definition: cpuid.h:80