/src/botan/src/lib/utils/cpuid/cpuid.cpp
Line | Count | Source (jump to first uncovered line) |
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/internal/parsing.h> |
12 | | #include <ostream> |
13 | | |
14 | | namespace Botan { |
15 | | |
16 | | bool CPUID::has_simd_32() |
17 | 0 | { |
18 | 0 | #if defined(BOTAN_TARGET_SUPPORTS_SSE2) |
19 | 0 | 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 | 0 | } |
28 | | |
29 | | //static |
30 | | std::string CPUID::to_string() |
31 | 0 | { |
32 | 0 | std::vector<std::string> flags; |
33 | |
|
34 | 0 | #define CPUID_PRINT(flag) do { if(has_##flag()) { flags.push_back(#flag); } } while(0) |
35 | |
|
36 | 0 | #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) |
37 | 0 | CPUID_PRINT(sse2); |
38 | 0 | CPUID_PRINT(ssse3); |
39 | 0 | CPUID_PRINT(sse41); |
40 | 0 | CPUID_PRINT(sse42); |
41 | 0 | CPUID_PRINT(avx2); |
42 | 0 | CPUID_PRINT(avx512f); |
43 | 0 | CPUID_PRINT(avx512dq); |
44 | 0 | CPUID_PRINT(avx512bw); |
45 | 0 | CPUID_PRINT(avx512_icelake); |
46 | |
|
47 | 0 | CPUID_PRINT(rdtsc); |
48 | 0 | CPUID_PRINT(bmi1); |
49 | 0 | CPUID_PRINT(bmi2); |
50 | 0 | CPUID_PRINT(adx); |
51 | |
|
52 | 0 | CPUID_PRINT(aes_ni); |
53 | 0 | CPUID_PRINT(clmul); |
54 | 0 | CPUID_PRINT(rdrand); |
55 | 0 | CPUID_PRINT(rdseed); |
56 | 0 | CPUID_PRINT(intel_sha); |
57 | 0 | CPUID_PRINT(avx512_aes); |
58 | 0 | CPUID_PRINT(avx512_clmul); |
59 | 0 | #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 | 0 | #undef CPUID_PRINT |
82 | |
|
83 | 0 | return string_join(flags, ' '); |
84 | 0 | } |
85 | | |
86 | | //static |
87 | | void CPUID::initialize() |
88 | 0 | { |
89 | 0 | state() = CPUID_Data(); |
90 | 0 | } |
91 | | |
92 | | CPUID::CPUID_Data::CPUID_Data() |
93 | 10 | { |
94 | 10 | m_cache_line_size = 0; |
95 | 10 | m_processor_features = 0; |
96 | | |
97 | 10 | #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \ |
98 | 10 | defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \ |
99 | 10 | defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) |
100 | | |
101 | 10 | m_processor_features = detect_cpu_features(&m_cache_line_size); |
102 | | |
103 | 10 | #endif |
104 | | |
105 | 10 | m_processor_features |= CPUID::CPUID_INITIALIZED_BIT; |
106 | | |
107 | 10 | if(m_cache_line_size == 0) |
108 | 0 | m_cache_line_size = BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE; |
109 | | |
110 | 10 | m_endian_status = runtime_check_endian(); |
111 | 10 | } |
112 | | |
113 | | //static |
114 | | CPUID::Endian_Status CPUID::CPUID_Data::runtime_check_endian() |
115 | 10 | { |
116 | | // Check runtime endian |
117 | 10 | const uint32_t endian32 = 0x01234567; |
118 | 10 | const uint8_t* e8 = reinterpret_cast<const uint8_t*>(&endian32); |
119 | | |
120 | 10 | CPUID::Endian_Status endian = CPUID::Endian_Status::Unknown; |
121 | | |
122 | 10 | if(e8[0] == 0x01 && e8[1] == 0x23 && e8[2] == 0x45 && e8[3] == 0x67) |
123 | 0 | { |
124 | 0 | endian = CPUID::Endian_Status::Big; |
125 | 0 | } |
126 | 10 | else if(e8[0] == 0x67 && e8[1] == 0x45 && e8[2] == 0x23 && e8[3] == 0x01) |
127 | 10 | { |
128 | 10 | endian = CPUID::Endian_Status::Little; |
129 | 10 | } |
130 | 0 | else |
131 | 0 | { |
132 | 0 | throw Internal_Error("Unexpected endian at runtime, neither big nor little"); |
133 | 0 | } |
134 | | |
135 | | // If we were compiled with a known endian, verify it matches at runtime |
136 | 10 | #if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) |
137 | 10 | BOTAN_ASSERT(endian == CPUID::Endian_Status::Little, "Build and runtime endian match"); |
138 | | #elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) |
139 | | BOTAN_ASSERT(endian == CPUID::Endian_Status::Big, "Build and runtime endian match"); |
140 | | #endif |
141 | | |
142 | 10 | return endian; |
143 | 10 | } |
144 | | |
145 | | std::vector<Botan::CPUID::CPUID_bits> |
146 | | CPUID::bit_from_string(const std::string& tok) |
147 | 0 | { |
148 | 0 | #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) |
149 | 0 | if(tok == "sse2" || tok == "simd") |
150 | 0 | return {Botan::CPUID::CPUID_SSE2_BIT}; |
151 | 0 | if(tok == "ssse3") |
152 | 0 | return {Botan::CPUID::CPUID_SSSE3_BIT}; |
153 | 0 | if(tok == "sse41") |
154 | 0 | return {Botan::CPUID::CPUID_SSE41_BIT}; |
155 | 0 | if(tok == "sse42") |
156 | 0 | return {Botan::CPUID::CPUID_SSE42_BIT}; |
157 | | // aes_ni is the string printed on the console when running "botan cpuid" |
158 | 0 | if(tok == "aesni" || tok == "aes_ni") |
159 | 0 | return {Botan::CPUID::CPUID_AESNI_BIT}; |
160 | 0 | if(tok == "clmul") |
161 | 0 | return {Botan::CPUID::CPUID_CLMUL_BIT}; |
162 | 0 | if(tok == "avx2") |
163 | 0 | return {Botan::CPUID::CPUID_AVX2_BIT}; |
164 | 0 | if(tok == "avx512f") |
165 | 0 | return {Botan::CPUID::CPUID_AVX512F_BIT}; |
166 | 0 | if(tok == "avx512_icelake") |
167 | 0 | return {Botan::CPUID::CPUID_AVX512_ICL_BIT}; |
168 | | // there were two if statements testing "sha" and "intel_sha" separately; combined |
169 | 0 | if(tok == "sha" || tok=="intel_sha") |
170 | 0 | return {Botan::CPUID::CPUID_SHA_BIT}; |
171 | 0 | if(tok == "rdtsc") |
172 | 0 | return {Botan::CPUID::CPUID_RDTSC_BIT}; |
173 | 0 | if(tok == "bmi1") |
174 | 0 | return {Botan::CPUID::CPUID_BMI1_BIT}; |
175 | 0 | if(tok == "bmi2") |
176 | 0 | return {Botan::CPUID::CPUID_BMI2_BIT}; |
177 | 0 | if(tok == "adx") |
178 | 0 | return {Botan::CPUID::CPUID_ADX_BIT}; |
179 | 0 | if(tok == "rdrand") |
180 | 0 | return {Botan::CPUID::CPUID_RDRAND_BIT}; |
181 | 0 | if(tok == "rdseed") |
182 | 0 | return {Botan::CPUID::CPUID_RDSEED_BIT}; |
183 | 0 | if(tok == "avx512_aes") |
184 | 0 | return {Botan::CPUID::CPUID_AVX512_AES_BIT}; |
185 | 0 | if(tok == "avx512_clmul") |
186 | 0 | return {Botan::CPUID::CPUID_AVX512_CLMUL_BIT}; |
187 | | |
188 | | #elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) |
189 | | if(tok == "altivec" || tok == "simd") |
190 | | return {Botan::CPUID::CPUID_ALTIVEC_BIT}; |
191 | | if(tok == "power_crypto") |
192 | | return {Botan::CPUID::CPUID_POWER_CRYPTO_BIT}; |
193 | | if(tok == "darn_rng") |
194 | | return {Botan::CPUID::CPUID_DARN_BIT}; |
195 | | |
196 | | #elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) |
197 | | if(tok == "neon" || tok == "simd") |
198 | | return {Botan::CPUID::CPUID_ARM_NEON_BIT}; |
199 | | if(tok == "arm_sve") |
200 | | return {Botan::CPUID::CPUID_ARM_SVE_BIT}; |
201 | | if(tok == "armv8sha1" || tok == "arm_sha1") |
202 | | return {Botan::CPUID::CPUID_ARM_SHA1_BIT}; |
203 | | if(tok == "armv8sha2" || tok == "arm_sha2") |
204 | | return {Botan::CPUID::CPUID_ARM_SHA2_BIT}; |
205 | | if(tok == "armv8aes" || tok == "arm_aes") |
206 | | return {Botan::CPUID::CPUID_ARM_AES_BIT}; |
207 | | if(tok == "armv8pmull" || tok == "arm_pmull") |
208 | | return {Botan::CPUID::CPUID_ARM_PMULL_BIT}; |
209 | | if(tok == "armv8sha3" || tok == "arm_sha3") |
210 | | return {Botan::CPUID::CPUID_ARM_SHA3_BIT}; |
211 | | if(tok == "armv8sha2_512" || tok == "arm_sha2_512") |
212 | | return {Botan::CPUID::CPUID_ARM_SHA2_512_BIT}; |
213 | | if(tok == "armv8sm3" || tok == "arm_sm3") |
214 | | return {Botan::CPUID::CPUID_ARM_SM3_BIT}; |
215 | | if(tok == "armv8sm4" || tok == "arm_sm4") |
216 | | return {Botan::CPUID::CPUID_ARM_SM4_BIT}; |
217 | | |
218 | | #else |
219 | | BOTAN_UNUSED(tok); |
220 | | #endif |
221 | | |
222 | 0 | return {}; |
223 | 0 | } |
224 | | |
225 | | } |