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