Botan 2.19.1
Crypto and TLS for C&
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
14namespace 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
30std::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 CPUID_PRINT(avx512dq);
44 CPUID_PRINT(avx512bw);
45 CPUID_PRINT(avx512_icelake);
46
47 CPUID_PRINT(rdtsc);
48 CPUID_PRINT(bmi1);
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 CPUID_PRINT(avx512_aes);
58 CPUID_PRINT(avx512_clmul);
59#endif
60
61#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
62 CPUID_PRINT(altivec);
63 CPUID_PRINT(power_crypto);
64 CPUID_PRINT(darn_rng);
65#endif
66
67#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
68 CPUID_PRINT(neon);
69 CPUID_PRINT(arm_sve);
70
71 CPUID_PRINT(arm_sha1);
72 CPUID_PRINT(arm_sha2);
73 CPUID_PRINT(arm_aes);
74 CPUID_PRINT(arm_pmull);
75 CPUID_PRINT(arm_sha2_512);
76 CPUID_PRINT(arm_sha3);
77 CPUID_PRINT(arm_sm3);
78 CPUID_PRINT(arm_sm4);
79#endif
80
81#undef CPUID_PRINT
82
83 return string_join(flags, ' ');
84 }
85
86//static
87void CPUID::print(std::ostream& o)
88 {
89 o << "CPUID flags: " << CPUID::to_string() << "\n";
90 }
91
92//static
94 {
95 state() = CPUID_Data();
96 }
97
98CPUID::CPUID_Data::CPUID_Data()
99 {
100 m_cache_line_size = 0;
101 m_processor_features = 0;
102
103#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \
104 defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
105 defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
106
107 m_processor_features = detect_cpu_features(&m_cache_line_size);
108
109#endif
110
111 m_processor_features |= CPUID::CPUID_INITIALIZED_BIT;
112
113 if(m_cache_line_size == 0)
114 m_cache_line_size = BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE;
115
116 m_endian_status = runtime_check_endian();
117 }
118
119//static
120CPUID::Endian_Status CPUID::CPUID_Data::runtime_check_endian()
121 {
122 // Check runtime endian
123 const uint32_t endian32 = 0x01234567;
124 const uint8_t* e8 = reinterpret_cast<const uint8_t*>(&endian32);
125
126 CPUID::Endian_Status endian = CPUID::Endian_Status::Unknown;
127
128 if(e8[0] == 0x01 && e8[1] == 0x23 && e8[2] == 0x45 && e8[3] == 0x67)
129 {
130 endian = CPUID::Endian_Status::Big;
131 }
132 else if(e8[0] == 0x67 && e8[1] == 0x45 && e8[2] == 0x23 && e8[3] == 0x01)
133 {
134 endian = CPUID::Endian_Status::Little;
135 }
136 else
137 {
138 throw Internal_Error("Unexpected endian at runtime, neither big nor little");
139 }
140
141 // If we were compiled with a known endian, verify it matches at runtime
142#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
143 BOTAN_ASSERT(endian == CPUID::Endian_Status::Little, "Build and runtime endian match");
144#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
145 BOTAN_ASSERT(endian == CPUID::Endian_Status::Big, "Build and runtime endian match");
146#endif
147
148 return endian;
149 }
150
151std::vector<Botan::CPUID::CPUID_bits>
152CPUID::bit_from_string(const std::string& tok)
153 {
154#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
155 if(tok == "sse2" || tok == "simd")
156 return {Botan::CPUID::CPUID_SSE2_BIT};
157 if(tok == "ssse3")
158 return {Botan::CPUID::CPUID_SSSE3_BIT};
159 if(tok == "sse41")
160 return {Botan::CPUID::CPUID_SSE41_BIT};
161 if(tok == "sse42")
162 return {Botan::CPUID::CPUID_SSE42_BIT};
163 // aes_ni is the string printed on the console when running "botan cpuid"
164 if(tok == "aesni" || tok == "aes_ni")
165 return {Botan::CPUID::CPUID_AESNI_BIT};
166 if(tok == "clmul")
167 return {Botan::CPUID::CPUID_CLMUL_BIT};
168 if(tok == "avx2")
169 return {Botan::CPUID::CPUID_AVX2_BIT};
170 if(tok == "avx512f")
171 return {Botan::CPUID::CPUID_AVX512F_BIT};
172 if(tok == "avx512_icelake")
173 return {Botan::CPUID::CPUID_AVX512_ICL_BIT};
174 // there were two if statements testing "sha" and "intel_sha" separately; combined
175 if(tok == "sha" || tok=="intel_sha")
176 return {Botan::CPUID::CPUID_SHA_BIT};
177 if(tok == "rdtsc")
178 return {Botan::CPUID::CPUID_RDTSC_BIT};
179 if(tok == "bmi1")
180 return {Botan::CPUID::CPUID_BMI1_BIT};
181 if(tok == "bmi2")
182 return {Botan::CPUID::CPUID_BMI2_BIT};
183 if(tok == "adx")
184 return {Botan::CPUID::CPUID_ADX_BIT};
185 if(tok == "rdrand")
186 return {Botan::CPUID::CPUID_RDRAND_BIT};
187 if(tok == "rdseed")
188 return {Botan::CPUID::CPUID_RDSEED_BIT};
189 if(tok == "avx512_aes")
190 return {Botan::CPUID::CPUID_AVX512_AES_BIT};
191 if(tok == "avx512_clmul")
192 return {Botan::CPUID::CPUID_AVX512_CLMUL_BIT};
193
194#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
195 if(tok == "altivec" || tok == "simd")
196 return {Botan::CPUID::CPUID_ALTIVEC_BIT};
197 if(tok == "power_crypto")
198 return {Botan::CPUID::CPUID_POWER_CRYPTO_BIT};
199 if(tok == "darn_rng")
200 return {Botan::CPUID::CPUID_DARN_BIT};
201
202#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
203 if(tok == "neon" || tok == "simd")
204 return {Botan::CPUID::CPUID_ARM_NEON_BIT};
205 if(tok == "arm_sve")
206 return {Botan::CPUID::CPUID_ARM_SVE_BIT};
207 if(tok == "armv8sha1" || tok == "arm_sha1")
208 return {Botan::CPUID::CPUID_ARM_SHA1_BIT};
209 if(tok == "armv8sha2" || tok == "arm_sha2")
210 return {Botan::CPUID::CPUID_ARM_SHA2_BIT};
211 if(tok == "armv8aes" || tok == "arm_aes")
212 return {Botan::CPUID::CPUID_ARM_AES_BIT};
213 if(tok == "armv8pmull" || tok == "arm_pmull")
214 return {Botan::CPUID::CPUID_ARM_PMULL_BIT};
215 if(tok == "armv8sha3" || tok == "arm_sha3")
216 return {Botan::CPUID::CPUID_ARM_SHA3_BIT};
217 if(tok == "armv8sha2_512" || tok == "arm_sha2_512")
218 return {Botan::CPUID::CPUID_ARM_SHA2_512_BIT};
219 if(tok == "armv8sm3" || tok == "arm_sm3")
220 return {Botan::CPUID::CPUID_ARM_SM3_BIT};
221 if(tok == "armv8sm4" || tok == "arm_sm4")
222 return {Botan::CPUID::CPUID_ARM_SM4_BIT};
223
224#else
225 BOTAN_UNUSED(tok);
226#endif
227
228 return {};
229 }
230
231}
#define BOTAN_UNUSED(...)
Definition: assert.h:142
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
static std::vector< CPUID::CPUID_bits > bit_from_string(const std::string &tok)
Definition: cpuid.cpp:152
static std::string to_string()
Definition: cpuid.cpp:30
static void print(std::ostream &o)
Definition: cpuid.cpp:87
static void initialize()
Definition: cpuid.cpp:93
@ CPUID_INITIALIZED_BIT
Definition: cpuid.h:148
static bool has_simd_32()
Definition: cpuid.cpp:16
#define CPUID_PRINT(flag)
Flags flags(Flag flags)
Definition: p11.h:860
Definition: alg_id.cpp:13
std::string string_join(const std::vector< std::string > &strs, char delim)
Definition: parsing.cpp:182