Coverage Report

Created: 2020-10-17 06:46

/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
0
   }
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
0
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
0
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
   m_cache_line_size = 0;
96
10
   m_processor_features = 0;
97
10
98
10
#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \
99
10
    defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
100
10
    defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
101
10
102
10
   m_processor_features = detect_cpu_features(&m_cache_line_size);
103
10
104
10
#endif
105
10
106
10
   m_processor_features |= CPUID::CPUID_INITIALIZED_BIT;
107
10
108
10
   if(m_cache_line_size == 0)
109
0
      m_cache_line_size = BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE;
110
10
111
10
   m_endian_status = runtime_check_endian();
112
10
   }
113
114
//static
115
CPUID::Endian_Status CPUID::CPUID_Data::runtime_check_endian()
116
10
   {
117
   // Check runtime endian
118
10
   const uint32_t endian32 = 0x01234567;
119
10
   const uint8_t* e8 = reinterpret_cast<const uint8_t*>(&endian32);
120
10
121
10
   CPUID::Endian_Status endian = CPUID::Endian_Status::Unknown;
122
10
123
10
   if(e8[0] == 0x01 && e8[1] == 0x23 && e8[2] == 0x45 && e8[3] == 0x67)
124
0
      {
125
0
      endian = CPUID::Endian_Status::Big;
126
0
      }
127
10
   else if(e8[0] == 0x67 && e8[1] == 0x45 && e8[2] == 0x23 && e8[3] == 0x01)
128
10
      {
129
10
      endian = CPUID::Endian_Status::Little;
130
10
      }
131
0
   else
132
0
      {
133
0
      throw Internal_Error("Unexpected endian at runtime, neither big nor little");
134
0
      }
135
10
136
   // If we were compiled with a known endian, verify it matches at runtime
137
10
#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
138
10
   BOTAN_ASSERT(endian == CPUID::Endian_Status::Little, "Build and runtime endian match");
139
#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
140
   BOTAN_ASSERT(endian == CPUID::Endian_Status::Big, "Build and runtime endian match");
141
#endif
142
10
143
10
   return endian;
144
10
   }
145
146
std::vector<Botan::CPUID::CPUID_bits>
147
CPUID::bit_from_string(const std::string& tok)
148
0
   {
149
0
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
150
0
   if(tok == "sse2" || tok == "simd")
151
0
      return {Botan::CPUID::CPUID_SSE2_BIT};
152
0
   if(tok == "ssse3")
153
0
      return {Botan::CPUID::CPUID_SSSE3_BIT};
154
0
   if(tok == "sse41")
155
0
      return {Botan::CPUID::CPUID_SSE41_BIT};
156
0
   if(tok == "sse42")
157
0
      return {Botan::CPUID::CPUID_SSE42_BIT};
158
   // aes_ni is the string printed on the console when running "botan cpuid"
159
0
   if(tok == "aesni" || tok == "aes_ni")
160
0
      return {Botan::CPUID::CPUID_AESNI_BIT};
161
0
   if(tok == "clmul")
162
0
      return {Botan::CPUID::CPUID_CLMUL_BIT};
163
0
   if(tok == "avx2")
164
0
      return {Botan::CPUID::CPUID_AVX2_BIT};
165
0
   if(tok == "avx512f")
166
0
      return {Botan::CPUID::CPUID_AVX512F_BIT};
167
   // there were two if statements testing "sha" and "intel_sha" separately; combined
168
0
   if(tok == "sha" || tok=="intel_sha")
169
0
      return {Botan::CPUID::CPUID_SHA_BIT};
170
0
   if(tok == "rdtsc")
171
0
      return {Botan::CPUID::CPUID_RDTSC_BIT};
172
0
   if(tok == "bmi1")
173
0
      return {Botan::CPUID::CPUID_BMI1_BIT};
174
0
   if(tok == "bmi2")
175
0
      return {Botan::CPUID::CPUID_BMI2_BIT};
176
0
   if(tok == "adx")
177
0
      return {Botan::CPUID::CPUID_ADX_BIT};
178
0
   if(tok == "rdrand")
179
0
      return {Botan::CPUID::CPUID_RDRAND_BIT};
180
0
   if(tok == "rdseed")
181
0
      return {Botan::CPUID::CPUID_RDSEED_BIT};
182
0
183
#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
184
   if(tok == "altivec" || tok == "simd")
185
      return {Botan::CPUID::CPUID_ALTIVEC_BIT};
186
   if(tok == "power_crypto")
187
      return {Botan::CPUID::CPUID_POWER_CRYPTO_BIT};
188
   if(tok == "darn_rng")
189
      return {Botan::CPUID::CPUID_DARN_BIT};
190
191
#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
192
   if(tok == "neon" || tok == "simd")
193
      return {Botan::CPUID::CPUID_ARM_NEON_BIT};
194
   if(tok == "arm_sve")
195
      return {Botan::CPUID::CPUID_ARM_SVE_BIT};
196
   if(tok == "armv8sha1" || tok == "arm_sha1")
197
      return {Botan::CPUID::CPUID_ARM_SHA1_BIT};
198
   if(tok == "armv8sha2" || tok == "arm_sha2")
199
      return {Botan::CPUID::CPUID_ARM_SHA2_BIT};
200
   if(tok == "armv8aes" || tok == "arm_aes")
201
      return {Botan::CPUID::CPUID_ARM_AES_BIT};
202
   if(tok == "armv8pmull" || tok == "arm_pmull")
203
      return {Botan::CPUID::CPUID_ARM_PMULL_BIT};
204
   if(tok == "armv8sha3" || tok == "arm_sha3")
205
      return {Botan::CPUID::CPUID_ARM_SHA3_BIT};
206
   if(tok == "armv8sha2_512" || tok == "arm_sha2_512")
207
      return {Botan::CPUID::CPUID_ARM_SHA2_512_BIT};
208
   if(tok == "armv8sm3" || tok == "arm_sm3")
209
      return {Botan::CPUID::CPUID_ARM_SM3_BIT};
210
   if(tok == "armv8sm4" || tok == "arm_sm4")
211
      return {Botan::CPUID::CPUID_ARM_SM4_BIT};
212
213
#else
214
   BOTAN_UNUSED(tok);
215
#endif
216
0
217
0
   return {};
218
0
   }
219
220
}