/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/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 | | } |
28 | | |
29 | | //static |
30 | | std::string CPUID::to_string() |
31 | 0 | { |
32 | 0 | std::vector<std::string> flags; |
33 | 0 |
|
34 | 0 | #define CPUID_PRINT(flag) do { if(has_##flag()) { flags.push_back(#flag); } } while(0) |
35 | 0 |
|
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 |
|
44 | 0 | CPUID_PRINT(rdtsc); |
45 | 0 | CPUID_PRINT(bmi1); |
46 | 0 | CPUID_PRINT(bmi2); |
47 | 0 | CPUID_PRINT(adx); |
48 | 0 |
|
49 | 0 | CPUID_PRINT(aes_ni); |
50 | 0 | CPUID_PRINT(clmul); |
51 | 0 | CPUID_PRINT(rdrand); |
52 | 0 | CPUID_PRINT(rdseed); |
53 | 0 | CPUID_PRINT(intel_sha); |
54 | 0 | #endif |
55 | 0 |
|
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 | 0 | #undef CPUID_PRINT |
77 | 0 |
|
78 | 0 | return string_join(flags, ' '); |
79 | 0 | } |
80 | | |
81 | | //static |
82 | | void CPUID::print(std::ostream& o) |
83 | 0 | { |
84 | 0 | o << "CPUID flags: " << CPUID::to_string() << "\n"; |
85 | 0 | } |
86 | | |
87 | | //static |
88 | | void CPUID::initialize() |
89 | 0 | { |
90 | 0 | state() = CPUID_Data(); |
91 | 0 | } |
92 | | |
93 | | CPUID::CPUID_Data::CPUID_Data() |
94 | 10 | { |
95 | 10 | #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \ |
96 | 10 | defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \ |
97 | 10 | defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) |
98 | 10 | |
99 | 10 | m_cache_line_size = 0; |
100 | 10 | m_processor_features = detect_cpu_features(&m_cache_line_size); |
101 | 10 | |
102 | 10 | #endif |
103 | 10 | |
104 | 10 | m_processor_features |= CPUID::CPUID_INITIALIZED_BIT; |
105 | 10 | |
106 | 10 | if(m_cache_line_size == 0) |
107 | 0 | m_cache_line_size = BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE; |
108 | 10 | |
109 | 10 | m_endian_status = runtime_check_endian(); |
110 | 10 | } |
111 | | |
112 | | //static |
113 | | CPUID::Endian_Status CPUID::CPUID_Data::runtime_check_endian() |
114 | 10 | { |
115 | 10 | // Check runtime endian |
116 | 10 | const uint32_t endian32 = 0x01234567; |
117 | 10 | const uint8_t* e8 = reinterpret_cast<const uint8_t*>(&endian32); |
118 | 10 | |
119 | 10 | CPUID::Endian_Status endian = CPUID::Endian_Status::Unknown; |
120 | 10 | |
121 | 10 | if(e8[0] == 0x01 && e8[1] == 0x23 && e8[2] == 0x45 && e8[3] == 0x67) |
122 | 0 | { |
123 | 0 | endian = CPUID::Endian_Status::Big; |
124 | 0 | } |
125 | 10 | else if(e8[0] == 0x67 && e8[1] == 0x45 && e8[2] == 0x23 && e8[3] == 0x01) |
126 | 10 | { |
127 | 10 | endian = CPUID::Endian_Status::Little; |
128 | 10 | } |
129 | 0 | else |
130 | 0 | { |
131 | 0 | throw Internal_Error("Unexpected endian at runtime, neither big nor little"); |
132 | 0 | } |
133 | 10 | |
134 | 10 | // If we were compiled with a known endian, verify it matches at runtime |
135 | 10 | #if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) |
136 | 10 | 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 | 10 | return endian; |
142 | 10 | } |
143 | | |
144 | | std::vector<Botan::CPUID::CPUID_bits> |
145 | | CPUID::bit_from_string(const std::string& tok) |
146 | 0 | { |
147 | 0 | #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) |
148 | 0 | if(tok == "sse2" || tok == "simd") |
149 | 0 | return {Botan::CPUID::CPUID_SSE2_BIT}; |
150 | 0 | if(tok == "ssse3") |
151 | 0 | return {Botan::CPUID::CPUID_SSSE3_BIT}; |
152 | 0 | if(tok == "aesni") |
153 | 0 | return {Botan::CPUID::CPUID_AESNI_BIT}; |
154 | 0 | if(tok == "clmul") |
155 | 0 | return {Botan::CPUID::CPUID_CLMUL_BIT}; |
156 | 0 | if(tok == "avx2") |
157 | 0 | return {Botan::CPUID::CPUID_AVX2_BIT}; |
158 | 0 | if(tok == "sha") |
159 | 0 | return {Botan::CPUID::CPUID_SHA_BIT}; |
160 | 0 | if(tok == "bmi2") |
161 | 0 | return {Botan::CPUID::CPUID_BMI2_BIT}; |
162 | 0 | if(tok == "adx") |
163 | 0 | return {Botan::CPUID::CPUID_ADX_BIT}; |
164 | 0 | if(tok == "intel_sha") |
165 | 0 | return {Botan::CPUID::CPUID_SHA_BIT}; |
166 | 0 | |
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 | 0 | return {}; |
198 | 0 | } |
199 | | |
200 | | } |