Coverage Report

Created: 2020-09-16 07:52

/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
#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
   // 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
   // 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
10
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 == "sse41")
153
0
      return {Botan::CPUID::CPUID_SSE41_BIT};
154
0
   if(tok == "sse42")
155
0
      return {Botan::CPUID::CPUID_SSE42_BIT};
156
   // aes_ni is the string printed on the console when running "botan cpuid"
157
0
   if(tok == "aesni" || tok == "aes_ni")
158
0
      return {Botan::CPUID::CPUID_AESNI_BIT};
159
0
   if(tok == "clmul")
160
0
      return {Botan::CPUID::CPUID_CLMUL_BIT};
161
0
   if(tok == "avx2")
162
0
      return {Botan::CPUID::CPUID_AVX2_BIT};
163
0
   if(tok == "avx512f")
164
0
      return {Botan::CPUID::CPUID_AVX512F_BIT};
165
   // there were two if statements testing "sha" and "intel_sha" separately; combined
166
0
   if(tok == "sha" || tok=="intel_sha")
167
0
      return {Botan::CPUID::CPUID_SHA_BIT};
168
0
   if(tok == "rdtsc")
169
0
      return {Botan::CPUID::CPUID_RDTSC_BIT};
170
0
   if(tok == "bmi1")
171
0
      return {Botan::CPUID::CPUID_BMI1_BIT};
172
0
   if(tok == "bmi2")
173
0
      return {Botan::CPUID::CPUID_BMI2_BIT};
174
0
   if(tok == "adx")
175
0
      return {Botan::CPUID::CPUID_ADX_BIT};
176
0
   if(tok == "rdrand")
177
0
      return {Botan::CPUID::CPUID_RDRAND_BIT};
178
0
   if(tok == "rdseed")
179
0
      return {Botan::CPUID::CPUID_RDSEED_BIT};
180
0
181
#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
182
   if(tok == "altivec" || tok == "simd")
183
      return {Botan::CPUID::CPUID_ALTIVEC_BIT};
184
   if(tok == "power_crypto")
185
      return {Botan::CPUID::CPUID_POWER_CRYPTO_BIT};
186
   if(tok == "darn_rng")
187
      return {Botan::CPUID::CPUID_DARN_BIT};
188
189
#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
190
   if(tok == "neon" || tok == "simd")
191
      return {Botan::CPUID::CPUID_ARM_NEON_BIT};
192
   if(tok == "arm_sve")
193
      return {Botan::CPUID::CPUID_ARM_SVE_BIT};
194
   if(tok == "armv8sha1" || tok == "arm_sha1")
195
      return {Botan::CPUID::CPUID_ARM_SHA1_BIT};
196
   if(tok == "armv8sha2" || tok == "arm_sha2")
197
      return {Botan::CPUID::CPUID_ARM_SHA2_BIT};
198
   if(tok == "armv8aes" || tok == "arm_aes")
199
      return {Botan::CPUID::CPUID_ARM_AES_BIT};
200
   if(tok == "armv8pmull" || tok == "arm_pmull")
201
      return {Botan::CPUID::CPUID_ARM_PMULL_BIT};
202
   if(tok == "armv8sha3" || tok == "arm_sha3")
203
      return {Botan::CPUID::CPUID_ARM_SHA3_BIT};
204
   if(tok == "armv8sha2_512" || tok == "arm_sha2_512")
205
      return {Botan::CPUID::CPUID_ARM_SHA2_512_BIT};
206
   if(tok == "armv8sm3" || tok == "arm_sm3")
207
      return {Botan::CPUID::CPUID_ARM_SM3_BIT};
208
   if(tok == "armv8sm4" || tok == "arm_sm4")
209
      return {Botan::CPUID::CPUID_ARM_SM4_BIT};
210
211
#else
212
   BOTAN_UNUSED(tok);
213
#endif
214
0
215
0
   return {};
216
0
   }
217
218
}