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