Botan  2.7.0
Crypto and TLS for C++11
cpuid.cpp
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 #include <botan/cpuid.h>
9 #include <botan/types.h>
10 #include <botan/exceptn.h>
11 #include <botan/parsing.h>
12 #include <ostream>
13 
14 namespace Botan {
15 
16 uint64_t CPUID::g_processor_features = 0;
17 size_t CPUID::g_cache_line_size = BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE;
18 CPUID::Endian_status CPUID::g_endian_status = ENDIAN_UNKNOWN;
19 
21  {
22 #if defined(BOTAN_TARGET_SUPPORTS_SSE2)
23  return CPUID::has_sse2();
24 #elif defined(BOTAN_TARGET_SUPPORTS_ALTIVEC)
25  return CPUID::has_altivec();
26 #elif defined(BOTAN_TARGET_SUPPORTS_NEON)
27  return CPUID::has_neon();
28 #else
29  return true;
30 #endif
31  }
32 
33 //static
34 std::string CPUID::to_string()
35  {
36  std::vector<std::string> flags;
37 
38 #define CPUID_PRINT(flag) do { if(has_##flag()) { flags.push_back(#flag); } } while(0)
39 
40 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
41  CPUID_PRINT(sse2);
42  CPUID_PRINT(ssse3);
43  CPUID_PRINT(sse41);
44  CPUID_PRINT(sse42);
45  CPUID_PRINT(avx2);
46  CPUID_PRINT(avx512f);
47 
48  CPUID_PRINT(rdtsc);
49  CPUID_PRINT(bmi1);
50  CPUID_PRINT(bmi2);
51  CPUID_PRINT(adx);
52 
53  CPUID_PRINT(aes_ni);
54  CPUID_PRINT(clmul);
55  CPUID_PRINT(rdrand);
56  CPUID_PRINT(rdseed);
57  CPUID_PRINT(intel_sha);
58 #endif
59 
60 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
61  CPUID_PRINT(altivec);
62  CPUID_PRINT(ppc_crypto);
63 #endif
64 
65 #if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
66  CPUID_PRINT(neon);
67  CPUID_PRINT(arm_sha1);
68  CPUID_PRINT(arm_sha2);
69  CPUID_PRINT(arm_aes);
70  CPUID_PRINT(arm_pmull);
71 #endif
72 
73 #undef CPUID_PRINT
74 
75  return string_join(flags, ' ');
76  }
77 
78 //static
79 void CPUID::print(std::ostream& o)
80  {
81  o << "CPUID flags: " << CPUID::to_string() << "\n";
82  }
83 
84 //static
86  {
87  g_processor_features = 0;
88 
89 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \
90  defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
91  defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
92 
93  g_processor_features = CPUID::detect_cpu_features(&g_cache_line_size);
94 
95 #endif
96 
97  g_endian_status = runtime_check_endian();
98  g_processor_features |= CPUID::CPUID_INITIALIZED_BIT;
99  }
100 
101 //static
102 CPUID::Endian_status CPUID::runtime_check_endian()
103  {
104  // Check runtime endian
105  const uint32_t endian32 = 0x01234567;
106  const uint8_t* e8 = reinterpret_cast<const uint8_t*>(&endian32);
107 
108  Endian_status endian = ENDIAN_UNKNOWN;
109 
110  if(e8[0] == 0x01 && e8[1] == 0x23 && e8[2] == 0x45 && e8[3] == 0x67)
111  {
112  endian = ENDIAN_BIG;
113  }
114  else if(e8[0] == 0x67 && e8[1] == 0x45 && e8[2] == 0x23 && e8[3] == 0x01)
115  {
116  endian = ENDIAN_LITTLE;
117  }
118  else
119  {
120  throw Internal_Error("Unexpected endian at runtime, neither big nor little");
121  }
122 
123  // If we were compiled with a known endian, verify it matches at runtime
124 #if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
125  BOTAN_ASSERT(endian == ENDIAN_LITTLE, "Build and runtime endian match");
126 #elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
127  BOTAN_ASSERT(endian == ENDIAN_BIG, "Build and runtime endian match");
128 #endif
129 
130  return endian;
131  }
132 
133 std::vector<Botan::CPUID::CPUID_bits>
134 CPUID::bit_from_string(const std::string& tok)
135  {
136 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
137  if(tok == "sse2" || tok == "simd")
138  return {Botan::CPUID::CPUID_SSE2_BIT};
139  if(tok == "ssse3")
140  return {Botan::CPUID::CPUID_SSSE3_BIT};
141  if(tok == "aesni")
142  return {Botan::CPUID::CPUID_AESNI_BIT};
143  if(tok == "clmul")
144  return {Botan::CPUID::CPUID_CLMUL_BIT};
145  if(tok == "avx2")
146  return {Botan::CPUID::CPUID_AVX2_BIT};
147  if(tok == "sha")
148  return {Botan::CPUID::CPUID_SHA_BIT};
149  if(tok == "bmi2")
150  return {Botan::CPUID::CPUID_BMI2_BIT};
151  if(tok == "adx")
152  return {Botan::CPUID::CPUID_ADX_BIT};
153  if(tok == "intel_sha")
154  return {Botan::CPUID::CPUID_SHA_BIT};
155 
156 #elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
157  if(tok == "altivec" || tok == "simd")
158  return {Botan::CPUID::CPUID_ALTIVEC_BIT};
159 
160 #elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
161  if(tok == "neon" || tok == "simd")
162  return {Botan::CPUID::CPUID_ARM_NEON_BIT};
163  if(tok == "armv8sha1")
164  return {Botan::CPUID::CPUID_ARM_SHA1_BIT};
165  if(tok == "armv8sha2")
166  return {Botan::CPUID::CPUID_ARM_SHA2_BIT};
167  if(tok == "armv8aes")
168  return {Botan::CPUID::CPUID_ARM_AES_BIT};
169  if(tok == "armv8pmull")
170  return {Botan::CPUID::CPUID_ARM_PMULL_BIT};
171 
172 #else
173  BOTAN_UNUSED(tok);
174 #endif
175 
176  return {};
177  }
178 
179 }
Flags flags(Flag flags)
Definition: p11.h:858
static bool has_simd_32()
Definition: cpuid.cpp:20
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:43
static std::string to_string()
Definition: cpuid.cpp:34
static std::vector< CPUID::CPUID_bits > bit_from_string(const std::string &tok)
Definition: cpuid.cpp:134
Definition: alg_id.cpp:13
#define BOTAN_UNUSED(...)
Definition: assert.h:130
static void print(std::ostream &o)
Definition: cpuid.cpp:79
static void initialize()
Definition: cpuid.cpp:85
#define CPUID_PRINT(flag)
std::string string_join(const std::vector< std::string > &strs, char delim)
Definition: parsing.cpp:178