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