Coverage Report

Created: 2020-11-21 08:34

/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
}