Botan  2.8.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_sve);
68 
69  CPUID_PRINT(arm_sha1);
70  CPUID_PRINT(arm_sha2);
71  CPUID_PRINT(arm_aes);
72  CPUID_PRINT(arm_pmull);
73  CPUID_PRINT(arm_sha2_512);
74  CPUID_PRINT(arm_sha3);
75  CPUID_PRINT(arm_sm3);
76  CPUID_PRINT(arm_sm4);
77 #endif
78 
79 #undef CPUID_PRINT
80 
81  return string_join(flags, ' ');
82  }
83 
84 //static
85 void CPUID::print(std::ostream& o)
86  {
87  o << "CPUID flags: " << CPUID::to_string() << "\n";
88  }
89 
90 //static
92  {
93  g_processor_features = 0;
94 
95 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \
96  defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
97  defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
98 
99  g_processor_features = CPUID::detect_cpu_features(&g_cache_line_size);
100 
101 #endif
102 
103  g_endian_status = runtime_check_endian();
104  g_processor_features |= CPUID::CPUID_INITIALIZED_BIT;
105  }
106 
107 //static
108 CPUID::Endian_status CPUID::runtime_check_endian()
109  {
110  // Check runtime endian
111  const uint32_t endian32 = 0x01234567;
112  const uint8_t* e8 = reinterpret_cast<const uint8_t*>(&endian32);
113 
114  Endian_status endian = ENDIAN_UNKNOWN;
115 
116  if(e8[0] == 0x01 && e8[1] == 0x23 && e8[2] == 0x45 && e8[3] == 0x67)
117  {
118  endian = ENDIAN_BIG;
119  }
120  else if(e8[0] == 0x67 && e8[1] == 0x45 && e8[2] == 0x23 && e8[3] == 0x01)
121  {
122  endian = ENDIAN_LITTLE;
123  }
124  else
125  {
126  throw Internal_Error("Unexpected endian at runtime, neither big nor little");
127  }
128 
129  // If we were compiled with a known endian, verify it matches at runtime
130 #if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
131  BOTAN_ASSERT(endian == ENDIAN_LITTLE, "Build and runtime endian match");
132 #elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
133  BOTAN_ASSERT(endian == ENDIAN_BIG, "Build and runtime endian match");
134 #endif
135 
136  return endian;
137  }
138 
139 std::vector<Botan::CPUID::CPUID_bits>
140 CPUID::bit_from_string(const std::string& tok)
141  {
142 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
143  if(tok == "sse2" || tok == "simd")
144  return {Botan::CPUID::CPUID_SSE2_BIT};
145  if(tok == "ssse3")
146  return {Botan::CPUID::CPUID_SSSE3_BIT};
147  if(tok == "aesni")
148  return {Botan::CPUID::CPUID_AESNI_BIT};
149  if(tok == "clmul")
150  return {Botan::CPUID::CPUID_CLMUL_BIT};
151  if(tok == "avx2")
152  return {Botan::CPUID::CPUID_AVX2_BIT};
153  if(tok == "sha")
154  return {Botan::CPUID::CPUID_SHA_BIT};
155  if(tok == "bmi2")
156  return {Botan::CPUID::CPUID_BMI2_BIT};
157  if(tok == "adx")
158  return {Botan::CPUID::CPUID_ADX_BIT};
159  if(tok == "intel_sha")
160  return {Botan::CPUID::CPUID_SHA_BIT};
161 
162 #elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
163  if(tok == "altivec" || tok == "simd")
164  return {Botan::CPUID::CPUID_ALTIVEC_BIT};
165  if(tok == "ppc_crypto")
166  return {Botan::CPUID::CPUID_PPC_CRYPTO_BIT};
167 
168 #elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
169  if(tok == "neon" || tok == "simd")
170  return {Botan::CPUID::CPUID_ARM_NEON_BIT};
171  if(tok == "armv8sha1")
172  return {Botan::CPUID::CPUID_ARM_SHA1_BIT};
173  if(tok == "armv8sha2")
174  return {Botan::CPUID::CPUID_ARM_SHA2_BIT};
175  if(tok == "armv8aes")
176  return {Botan::CPUID::CPUID_ARM_AES_BIT};
177  if(tok == "armv8pmull")
178  return {Botan::CPUID::CPUID_ARM_PMULL_BIT};
179  if(tok == "armv8sha3")
180  return {Botan::CPUID::CPUID_ARM_SHA3_BIT};
181  if(tok == "armv8sha2_512")
182  return {Botan::CPUID::CPUID_ARM_SHA2_512_BIT};
183  if(tok == "armv8sm3")
184  return {Botan::CPUID::CPUID_ARM_SM3_BIT};
185  if(tok == "armv8sm4")
186  return {Botan::CPUID::CPUID_ARM_SM4_BIT};
187 
188 #else
189  BOTAN_UNUSED(tok);
190 #endif
191 
192  return {};
193  }
194 
195 }
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:55
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:140
Definition: alg_id.cpp:13
#define BOTAN_UNUSED(...)
Definition: assert.h:142
static void print(std::ostream &o)
Definition: cpuid.cpp:85
static void initialize()
Definition: cpuid.cpp:91
#define CPUID_PRINT(flag)
std::string string_join(const std::vector< std::string > &strs, char delim)
Definition: parsing.cpp:178