Coverage Report

Created: 2021-05-04 09:02

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