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