8#include <botan/cpuid.h>
9#include <botan/mem_ops.h>
10#include <botan/loadstor.h>
12#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
14#if defined(BOTAN_BUILD_COMPILER_IS_MSVC)
16#elif defined(BOTAN_BUILD_COMPILER_IS_INTEL)
17 #include <ia32intrin.h>
18#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG)
26#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
28uint64_t CPUID::CPUID_Data::detect_cpu_features(
size_t* cache_line_size)
30#if defined(BOTAN_BUILD_COMPILER_IS_MSVC)
31 #define X86_CPUID(type, out) do { __cpuid((int*)out, type); } while(0)
32 #define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0)
34#elif defined(BOTAN_BUILD_COMPILER_IS_INTEL)
35 #define X86_CPUID(type, out) do { __cpuid(out, type); } while(0)
36 #define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0)
38#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && defined(BOTAN_USE_GCC_INLINE_ASM)
39 #define X86_CPUID(type, out) \
40 asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \
43 #define X86_CPUID_SUBLEVEL(type, level, out) \
44 asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \
45 : "0" (type), "2" (level))
47#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG)
48 #define X86_CPUID(type, out) do { __get_cpuid(type, out, out+1, out+2, out+3); } while(0)
50 #define X86_CPUID_SUBLEVEL(type, level, out) \
51 do { __cpuid_count(type, level, out[0], out[1], out[2], out[3]); } while(0)
53 #warning "No way of calling x86 cpuid instruction for this compiler"
54 #define X86_CPUID(type, out) do { clear_mem(out, 4); } while(0)
55 #define X86_CPUID_SUBLEVEL(type, level, out) do { clear_mem(out, 4); } while(0)
58 uint64_t features_detected = 0;
59 uint32_t cpuid[4] = { 0 };
65 const uint32_t max_supported_sublevel = cpuid[0];
67 const uint32_t INTEL_CPUID[3] = { 0x756E6547, 0x6C65746E, 0x49656E69 };
68 const uint32_t AMD_CPUID[3] = { 0x68747541, 0x444D4163, 0x69746E65 };
69 const bool is_intel =
same_mem(cpuid + 1, INTEL_CPUID, 3);
70 const bool is_amd =
same_mem(cpuid + 1, AMD_CPUID, 3);
72 if(max_supported_sublevel >= 1)
76 const uint64_t flags0 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[3];
78 enum x86_CPUID_1_bits : uint64_t {
86 OSXSAVE = (1ULL << 59),
91 if(flags0 & x86_CPUID_1_bits::RDTSC)
92 features_detected |= CPUID::CPUID_RDTSC_BIT;
93 if(flags0 & x86_CPUID_1_bits::SSE2)
94 features_detected |= CPUID::CPUID_SSE2_BIT;
95 if(flags0 & x86_CPUID_1_bits::CLMUL)
96 features_detected |= CPUID::CPUID_CLMUL_BIT;
97 if(flags0 & x86_CPUID_1_bits::SSSE3)
98 features_detected |= CPUID::CPUID_SSSE3_BIT;
99 if(flags0 & x86_CPUID_1_bits::SSE41)
100 features_detected |= CPUID::CPUID_SSE41_BIT;
101 if(flags0 & x86_CPUID_1_bits::SSE42)
102 features_detected |= CPUID::CPUID_SSE42_BIT;
103 if(flags0 & x86_CPUID_1_bits::AESNI)
104 features_detected |= CPUID::CPUID_AESNI_BIT;
105 if(flags0 & x86_CPUID_1_bits::RDRAND)
106 features_detected |= CPUID::CPUID_RDRAND_BIT;
107 if((flags0 & x86_CPUID_1_bits::AVX) &&
108 (flags0 & x86_CPUID_1_bits::OSXSAVE))
115 *cache_line_size = 8 *
get_byte(2, cpuid[1]);
120 X86_CPUID(0x80000005, cpuid);
121 *cache_line_size =
get_byte(3, cpuid[2]);
124 if(max_supported_sublevel >= 7)
127 X86_CPUID_SUBLEVEL(7, 0, cpuid);
129 enum x86_CPUID_7_bits : uint64_t {
133 AVX512_F = (1ULL << 16),
134 AVX512_DQ = (1ULL << 17),
135 RDSEED = (1ULL << 18),
137 AVX512_IFMA = (1ULL << 21),
139 AVX512_BW = (1ULL << 30),
140 AVX512_VL = (1ULL << 31),
141 AVX512_VBMI = (1ULL << 33),
142 AVX512_VBMI2 = (1ULL << 38),
143 AVX512_VAES = (1ULL << 41),
144 AVX512_VCLMUL = (1ULL << 42),
145 AVX512_VBITALG = (1ULL << 44),
148 const uint64_t flags7 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[1];
150 if((flags7 & x86_CPUID_7_bits::AVX2) && has_avx)
151 features_detected |= CPUID::CPUID_AVX2_BIT;
152 if(flags7 & x86_CPUID_7_bits::BMI1)
154 features_detected |= CPUID::CPUID_BMI1_BIT;
160 if(flags7 & x86_CPUID_7_bits::BMI2)
161 features_detected |= CPUID::CPUID_BMI2_BIT;
164 if((flags7 & x86_CPUID_7_bits::AVX512_F) && has_avx)
166 features_detected |= CPUID::CPUID_AVX512F_BIT;
168 if(flags7 & x86_CPUID_7_bits::AVX512_DQ)
169 features_detected |= CPUID::CPUID_AVX512DQ_BIT;
170 if(flags7 & x86_CPUID_7_bits::AVX512_BW)
171 features_detected |= CPUID::CPUID_AVX512BW_BIT;
173 const uint64_t ICELAKE_FLAGS =
174 x86_CPUID_7_bits::AVX512_F |
175 x86_CPUID_7_bits::AVX512_DQ |
176 x86_CPUID_7_bits::AVX512_IFMA |
177 x86_CPUID_7_bits::AVX512_BW |
178 x86_CPUID_7_bits::AVX512_VL |
179 x86_CPUID_7_bits::AVX512_VBMI |
180 x86_CPUID_7_bits::AVX512_VBMI2 |
181 x86_CPUID_7_bits::AVX512_VBITALG;
183 if((flags7 & ICELAKE_FLAGS) == ICELAKE_FLAGS)
184 features_detected |= CPUID::CPUID_AVX512_ICL_BIT;
186 if(flags7 & x86_CPUID_7_bits::AVX512_VAES)
187 features_detected |= CPUID::CPUID_AVX512_AES_BIT;
188 if(flags7 & x86_CPUID_7_bits::AVX512_VCLMUL)
189 features_detected |= CPUID::CPUID_AVX512_CLMUL_BIT;
192 if(flags7 & x86_CPUID_7_bits::RDSEED)
193 features_detected |= CPUID::CPUID_RDSEED_BIT;
194 if(flags7 & x86_CPUID_7_bits::ADX)
195 features_detected |= CPUID::CPUID_ADX_BIT;
196 if(flags7 & x86_CPUID_7_bits::SHA)
197 features_detected |= CPUID::CPUID_SHA_BIT;
201#undef X86_CPUID_SUBLEVEL
207#if defined(BOTAN_TARGET_ARCH_IS_X86_64)
208 if(features_detected == 0)
210 features_detected |= CPUID::CPUID_SSE2_BIT;
211 features_detected |= CPUID::CPUID_RDTSC_BIT;
215 return features_detected;
bool same_mem(const T *p1, const T *p2, size_t n)
constexpr uint8_t get_byte(size_t byte_num, T input)
void clear_mem(T *ptr, size_t n)