• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 13212092742

08 Feb 2025 12:33AM UTC coverage: 91.658% (-0.004%) from 91.662%
13212092742

push

github

web-flow
Merge pull request #4642 from randombit/jack/target-info-header

Add internal target_info.h header

94839 of 103471 relevant lines covered (91.66%)

11295178.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.83
/src/lib/utils/cpuid/cpuid.cpp
1
/*
2
* Runtime CPU detection
3
* (C) 2009,2010,2013,2017,2023 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/internal/cpuid.h>
9

10
#include <botan/assert.h>
11
#include <botan/exceptn.h>
12
#include <botan/types.h>
13
#include <botan/internal/parsing.h>
14
#include <botan/internal/target_info.h>
15
#include <ostream>
16

17
#if defined(BOTAN_HAS_OS_UTILS)
18
   #include <botan/internal/os_utils.h>
19
#endif
20

21
namespace Botan {
22

23
//static
24
std::string CPUID::to_string() {
19✔
25
   std::vector<std::string> flags;
19✔
26

27
   auto append_fn = [&](bool flag, const char* flag_name) {
399✔
28
      if(flag) {
380✔
29
         flags.push_back(flag_name);
442✔
30
      }
31
   };
380✔
32

33
   // NOLINTNEXTLINE(*-macro-usage)
34
#define CPUID_PRINT(flag) append_fn(has_##flag(), #flag)
35

36
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
37
   CPUID_PRINT(rdtsc);
19✔
38

39
   CPUID_PRINT(sse2);
19✔
40
   CPUID_PRINT(ssse3);
19✔
41
   CPUID_PRINT(avx2);
19✔
42

43
   CPUID_PRINT(bmi2);
19✔
44
   CPUID_PRINT(adx);
19✔
45
   CPUID_PRINT(gfni);
19✔
46

47
   CPUID_PRINT(aes_ni);
19✔
48
   CPUID_PRINT(clmul);
19✔
49
   CPUID_PRINT(rdrand);
19✔
50
   CPUID_PRINT(rdseed);
19✔
51
   CPUID_PRINT(intel_sha);
19✔
52
   CPUID_PRINT(intel_sha512);
19✔
53

54
   CPUID_PRINT(avx2_vaes);
19✔
55
   CPUID_PRINT(avx2_clmul);
19✔
56

57
   CPUID_PRINT(avx512);
19✔
58
   CPUID_PRINT(avx512_aes);
19✔
59
   CPUID_PRINT(avx512_clmul);
19✔
60

61
   CPUID_PRINT(intel_sm3);
19✔
62
   CPUID_PRINT(intel_sm4);
19✔
63

64
#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
65
   CPUID_PRINT(altivec);
66
   CPUID_PRINT(power_crypto);
67
   CPUID_PRINT(darn_rng);
68
#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
69
   CPUID_PRINT(neon);
70
   CPUID_PRINT(arm_sve);
71

72
   CPUID_PRINT(arm_sha1);
73
   CPUID_PRINT(arm_sha2);
74
   CPUID_PRINT(arm_aes);
75
   CPUID_PRINT(arm_pmull);
76
   CPUID_PRINT(arm_sha2_512);
77
   CPUID_PRINT(arm_sha3);
78
   CPUID_PRINT(arm_sm3);
79
   CPUID_PRINT(arm_sm4);
80
#else
81
   BOTAN_UNUSED(append_fn);
82
#endif
83

84
#undef CPUID_PRINT
85

86
   return string_join(flags, ' ');
38✔
87
}
19✔
88

89
//static
90
void CPUID::initialize() {
5,629✔
91
   state() = CPUID_Data();
5,629✔
92
}
5,629✔
93

94
namespace {
95

96
// Returns true if big-endian
97
bool runtime_check_if_big_endian() {
13,018✔
98
   // Check runtime endian
99
   const uint32_t endian32 = 0x01234567;
13,018✔
100
   const uint8_t* e8 = reinterpret_cast<const uint8_t*>(&endian32);
13,018✔
101

102
   bool is_big_endian = false;
13,018✔
103

104
   if(e8[0] == 0x01 && e8[1] == 0x23 && e8[2] == 0x45 && e8[3] == 0x67) {
13,018✔
105
      is_big_endian = true;
106
   } else if(e8[0] == 0x67 && e8[1] == 0x45 && e8[2] == 0x23 && e8[3] == 0x01) {
13,018✔
107
      is_big_endian = false;
108
   } else {
109
      throw Internal_Error("Unexpected endian at runtime, neither big nor little");
110
   }
111

112
   // If we were compiled with a known endian, verify it matches at runtime
113
#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
114
   BOTAN_ASSERT(!is_big_endian, "Build and runtime endian match");
13,018✔
115
#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
116
   BOTAN_ASSERT(is_big_endian, "Build and runtime endian match");
117
#endif
118

119
   return is_big_endian;
13,018✔
120
}
121

122
#if defined(BOTAN_CPUID_HAS_DETECTION)
123
uint32_t cleared_cpuid_bits() {
13,018✔
124
   uint32_t cleared = 0;
13,018✔
125

126
   #if defined(BOTAN_HAS_OS_UTILS)
127
   std::string clear_cpuid_env;
13,018✔
128
   if(OS::read_env_variable(clear_cpuid_env, "BOTAN_CLEAR_CPUID")) {
13,018✔
129
      for(const auto& cpuid : split_on(clear_cpuid_env, ',')) {
336✔
130
         for(auto& bit : CPUID::bit_from_string(cpuid)) {
336✔
131
            cleared |= bit;
168✔
132
         }
168✔
133
      }
168✔
134
   }
135
   #endif
136

137
   return cleared;
13,018✔
138
}
13,018✔
139
#endif
140

141
}  // namespace
142

143
CPUID::CPUID_Data::CPUID_Data() {
13,018✔
144
   m_processor_features = 0;
13,018✔
145

146
#if defined(BOTAN_CPUID_HAS_DETECTION)
147
   m_processor_features = detect_cpu_features(~cleared_cpuid_bits());
13,018✔
148
#endif
149

150
   m_processor_features |= CPUID::CPUID_INITIALIZED_BIT;
13,018✔
151

152
   if(runtime_check_if_big_endian()) {
13,018✔
153
      m_processor_features |= CPUID::CPUID_IS_BIG_ENDIAN_BIT;
154
   }
155
}
13,018✔
156

157
std::vector<CPUID::CPUID_bits> CPUID::bit_from_string(std::string_view tok) {
211✔
158
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
159
   if(tok == "sse2" || tok == "simd") {
232✔
160
      return {CPUID::CPUID_SSE2_BIT};
7✔
161
   } else if(tok == "ssse3") {
204✔
162
      return {CPUID::CPUID_SSSE3_BIT};
6✔
163
   } else if(tok == "aesni" || tok == "aes_ni") {
208✔
164
      // aes_ni is the string printed on the console when running "botan cpuid"
165
      return {CPUID::CPUID_AESNI_BIT};
4✔
166
   } else if(tok == "clmul") {
194✔
167
      return {CPUID::CPUID_CLMUL_BIT};
3✔
168
   } else if(tok == "avx2") {
191✔
169
      return {CPUID::CPUID_AVX2_BIT};
6✔
170
   } else if(tok == "avx512") {
185✔
171
      return {CPUID::CPUID_AVX512_BIT};
2✔
172
   }
173
   // there were two if statements testing "sha" and "intel_sha" separately; combined
174
   else if(tok == "sha" || tok == "intel_sha") {
188✔
175
      return {CPUID::CPUID_SHA_BIT};
4✔
176
   } else if(tok == "rdtsc") {
179✔
177
      return {CPUID::CPUID_RDTSC_BIT};
1✔
178
   } else if(tok == "bmi2") {
178✔
179
      return {CPUID::CPUID_BMI_BIT};
4✔
180
   } else if(tok == "adx") {
174✔
181
      return {CPUID::CPUID_ADX_BIT};
1✔
182
   } else if(tok == "gfni") {
173✔
183
      return {CPUID::CPUID_GFNI_BIT};
1✔
184
   } else if(tok == "rdrand") {
172✔
185
      return {CPUID::CPUID_RDRAND_BIT};
1✔
186
   } else if(tok == "rdseed") {
171✔
187
      return {CPUID::CPUID_RDSEED_BIT};
1✔
188
   } else if(tok == "avx512_aes") {
170✔
189
      return {CPUID::CPUID_AVX512_AES_BIT};
×
190
   } else if(tok == "avx512_clmul") {
170✔
191
      return {CPUID::CPUID_AVX512_CLMUL_BIT};
×
192
   } else if(tok == "avx2_vaes") {
170✔
193
      return {CPUID::CPUID_AVX2_AES_BIT};
2✔
194
   } else if(tok == "avx2_clmul") {
168✔
195
      return {CPUID::CPUID_AVX2_CLMUL_BIT};
156✔
196
   } else if(tok == "intel_sm3") {
12✔
197
      return {CPUID::CPUID_SM3_BIT};
×
198
   } else if(tok == "intel_sm4") {
12✔
199
      return {CPUID::CPUID_SM4_BIT};
×
200
   }
201

202
#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
203
   if(tok == "altivec" || tok == "simd") {
204
      return {CPUID::CPUID_ALTIVEC_BIT};
205
   } else if(tok == "power_crypto") {
206
      return {CPUID::CPUID_POWER_CRYPTO_BIT};
207
   } else if(tok == "darn_rng") {
208
      return {CPUID::CPUID_DARN_BIT};
209
   }
210

211
#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
212
   if(tok == "neon" || tok == "simd") {
213
      return {CPUID::CPUID_ARM_NEON_BIT};
214
   } else if(tok == "arm_sve") {
215
      return {CPUID::CPUID_ARM_SVE_BIT};
216
   } else if(tok == "armv8sha1" || tok == "arm_sha1") {
217
      return {CPUID::CPUID_ARM_SHA1_BIT};
218
   } else if(tok == "armv8sha2" || tok == "arm_sha2") {
219
      return {CPUID::CPUID_ARM_SHA2_BIT};
220
   } else if(tok == "armv8aes" || tok == "arm_aes") {
221
      return {CPUID::CPUID_ARM_AES_BIT};
222
   } else if(tok == "armv8pmull" || tok == "arm_pmull") {
223
      return {CPUID::CPUID_ARM_PMULL_BIT};
224
   } else if(tok == "armv8sha3" || tok == "arm_sha3") {
225
      return {CPUID::CPUID_ARM_SHA3_BIT};
226
   } else if(tok == "armv8sha2_512" || tok == "arm_sha2_512") {
227
      return {CPUID::CPUID_ARM_SHA2_512_BIT};
228
   } else if(tok == "armv8sm3" || tok == "arm_sm3") {
229
      return {CPUID::CPUID_ARM_SM3_BIT};
230
   } else if(tok == "armv8sm4" || tok == "arm_sm4") {
231
      return {CPUID::CPUID_ARM_SM4_BIT};
232
   }
233

234
#else
235
   BOTAN_UNUSED(tok);
236
#endif
237

238
   return {};
12✔
239
}
240

241
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc