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)
28 uint64_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 };
64 const uint32_t max_supported_sublevel = cpuid[0];
66 const uint32_t INTEL_CPUID[3] = { 0x756E6547, 0x6C65746E, 0x49656E69 };
67 const uint32_t AMD_CPUID[3] = { 0x68747541, 0x444D4163, 0x69746E65 };
68 const bool is_intel =
same_mem(cpuid + 1, INTEL_CPUID, 3);
69 const bool is_amd =
same_mem(cpuid + 1, AMD_CPUID, 3);
71 if(max_supported_sublevel >= 1)
75 const uint64_t flags0 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[3];
77 enum x86_CPUID_1_bits : uint64_t {
88 if(flags0 & x86_CPUID_1_bits::RDTSC)
89 features_detected |= CPUID::CPUID_RDTSC_BIT;
90 if(flags0 & x86_CPUID_1_bits::SSE2)
91 features_detected |= CPUID::CPUID_SSE2_BIT;
92 if(flags0 & x86_CPUID_1_bits::CLMUL)
93 features_detected |= CPUID::CPUID_CLMUL_BIT;
94 if(flags0 & x86_CPUID_1_bits::SSSE3)
95 features_detected |= CPUID::CPUID_SSSE3_BIT;
96 if(flags0 & x86_CPUID_1_bits::SSE41)
97 features_detected |= CPUID::CPUID_SSE41_BIT;
98 if(flags0 & x86_CPUID_1_bits::SSE42)
99 features_detected |= CPUID::CPUID_SSE42_BIT;
100 if(flags0 & x86_CPUID_1_bits::AESNI)
101 features_detected |= CPUID::CPUID_AESNI_BIT;
102 if(flags0 & x86_CPUID_1_bits::RDRAND)
103 features_detected |= CPUID::CPUID_RDRAND_BIT;
109 *cache_line_size = 8 *
get_byte(2, cpuid[1]);
114 X86_CPUID(0x80000005, cpuid);
115 *cache_line_size =
get_byte(3, cpuid[2]);
118 if(max_supported_sublevel >= 7)
121 X86_CPUID_SUBLEVEL(7, 0, cpuid);
123 enum x86_CPUID_7_bits : uint64_t {
127 AVX512F = (1ULL << 16),
128 RDSEED = (1ULL << 18),
132 uint64_t flags7 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[1];
134 if(flags7 & x86_CPUID_7_bits::AVX2)
135 features_detected |= CPUID::CPUID_AVX2_BIT;
136 if(flags7 & x86_CPUID_7_bits::BMI1)
138 features_detected |= CPUID::CPUID_BMI1_BIT;
144 if(flags7 & x86_CPUID_7_bits::BMI2)
145 features_detected |= CPUID::CPUID_BMI2_BIT;
148 if(flags7 & x86_CPUID_7_bits::AVX512F)
149 features_detected |= CPUID::CPUID_AVX512F_BIT;
150 if(flags7 & x86_CPUID_7_bits::RDSEED)
151 features_detected |= CPUID::CPUID_RDSEED_BIT;
152 if(flags7 & x86_CPUID_7_bits::ADX)
153 features_detected |= CPUID::CPUID_ADX_BIT;
154 if(flags7 & x86_CPUID_7_bits::SHA)
155 features_detected |= CPUID::CPUID_SHA_BIT;
159 #undef X86_CPUID_SUBLEVEL
165 #if defined(BOTAN_TARGET_ARCH_IS_X86_64)
166 if(features_detected == 0)
168 features_detected |= CPUID::CPUID_SSE2_BIT;
169 features_detected |= CPUID::CPUID_RDTSC_BIT;
173 return features_detected;
bool same_mem(const T *p1, const T *p2, size_t n)
void clear_mem(T *ptr, size_t n)
constexpr uint8_t get_byte(size_t byte_num, T input)