8#include <botan/internal/cpuid.h>
10#include <botan/mem_ops.h>
11#include <botan/internal/loadstor.h>
13#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
15 #include <immintrin.h>
17 #if defined(BOTAN_BUILD_COMPILER_IS_MSVC)
19 #elif defined(BOTAN_BUILD_COMPILER_IS_INTEL)
20 #include <ia32intrin.h>
21 #elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG)
29#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
33void invoke_cpuid(uint32_t type, uint32_t out[4]) {
34 #if defined(BOTAN_BUILD_COMPILER_IS_MSVC) || defined(BOTAN_BUILD_COMPILER_IS_INTEL)
35 __cpuid((
int*)out, type);
37 #elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG)
38 __get_cpuid(type, out, out + 1, out + 2, out + 3);
40 #elif defined(BOTAN_USE_GCC_INLINE_ASM)
41 asm(
"cpuid\n\t" :
"=a"(out[0]),
"=b"(out[1]),
"=c"(out[2]),
"=d"(out[3]) :
"0"(type));
44 #warning "No way of calling x86 cpuid instruction for this compiler"
53void invoke_cpuid_sublevel(uint32_t type, uint32_t level, uint32_t out[4]) {
54 #if defined(BOTAN_BUILD_COMPILER_IS_MSVC)
55 __cpuidex((
int*)out, type, level);
57 #elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG)
58 __cpuid_count(type, level, out[0], out[1], out[2], out[3]);
60 #elif defined(BOTAN_USE_GCC_INLINE_ASM)
61 asm(
"cpuid\n\t" :
"=a"(out[0]),
"=b"(out[1]),
"=c"(out[2]),
"=d"(out[3]) :
"0"(type),
"2"(level));
64 #warning "No way of calling x86 cpuid instruction for this compiler"
71uint32_t CPUID::CPUID_Data::detect_cpu_features() {
72 uint32_t features_detected = 0;
73 uint32_t cpuid[4] = {0};
74 bool has_os_ymm_support =
false;
75 bool has_os_zmm_support =
false;
78 invoke_cpuid(0, cpuid);
80 const uint32_t max_supported_sublevel = cpuid[0];
82 if(max_supported_sublevel >= 1) {
84 invoke_cpuid(1, cpuid);
85 const uint64_t flags0 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[3];
87 enum x86_CPUID_1_bits : uint64_t {
93 OSXSAVE = (1ULL << 59),
98 if(flags0 & x86_CPUID_1_bits::RDTSC) {
99 features_detected |= CPUID::CPUID_RDTSC_BIT;
101 if(flags0 & x86_CPUID_1_bits::SSE2) {
102 features_detected |= CPUID::CPUID_SSE2_BIT;
104 if(flags0 & x86_CPUID_1_bits::CLMUL) {
105 features_detected |= CPUID::CPUID_CLMUL_BIT;
107 if(flags0 & x86_CPUID_1_bits::SSSE3) {
108 features_detected |= CPUID::CPUID_SSSE3_BIT;
110 if(flags0 & x86_CPUID_1_bits::AESNI) {
111 features_detected |= CPUID::CPUID_AESNI_BIT;
113 if(flags0 & x86_CPUID_1_bits::RDRAND) {
114 features_detected |= CPUID::CPUID_RDRAND_BIT;
117 if((flags0 & x86_CPUID_1_bits::AVX) && (flags0 & x86_CPUID_1_bits::OSXSAVE)) {
118 const uint64_t xcr_flags = xgetbv();
119 if((xcr_flags & 0x6) == 0x6) {
120 has_os_ymm_support =
true;
121 has_os_zmm_support = (xcr_flags & 0xE0) == 0xE0;
126 if(max_supported_sublevel >= 7) {
128 invoke_cpuid_sublevel(7, 0, cpuid);
130 enum x86_CPUID_7_bits : uint64_t {
134 AVX512_F = (1ULL << 16),
135 AVX512_DQ = (1ULL << 17),
136 RDSEED = (1ULL << 18),
138 AVX512_IFMA = (1ULL << 21),
140 AVX512_BW = (1ULL << 30),
141 AVX512_VL = (1ULL << 31),
142 AVX512_VBMI = (1ULL << 33),
143 AVX512_VBMI2 = (1ULL << 38),
144 AVX512_VAES = (1ULL << 41),
145 AVX512_VCLMUL = (1ULL << 42),
146 AVX512_VBITALG = (1ULL << 44),
149 const uint64_t flags7 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[1];
151 if((flags7 & x86_CPUID_7_bits::AVX2) && has_os_ymm_support) {
152 features_detected |= CPUID::CPUID_AVX2_BIT;
154 if(flags7 & x86_CPUID_7_bits::RDSEED) {
155 features_detected |= CPUID::CPUID_RDSEED_BIT;
157 if(flags7 & x86_CPUID_7_bits::ADX) {
158 features_detected |= CPUID::CPUID_ADX_BIT;
160 if(flags7 & x86_CPUID_7_bits::SHA) {
161 features_detected |= CPUID::CPUID_SHA_BIT;
168 if((flags7 & x86_CPUID_7_bits::BMI1) && (flags7 & x86_CPUID_7_bits::BMI2)) {
169 features_detected |= CPUID::CPUID_BMI_BIT;
172 if((flags7 & x86_CPUID_7_bits::AVX512_F) && has_os_zmm_support) {
173 const uint64_t AVX512_PROFILE_FLAGS = x86_CPUID_7_bits::AVX512_F | x86_CPUID_7_bits::AVX512_DQ |
174 x86_CPUID_7_bits::AVX512_IFMA | x86_CPUID_7_bits::AVX512_BW |
175 x86_CPUID_7_bits::AVX512_VL | x86_CPUID_7_bits::AVX512_VBMI |
176 x86_CPUID_7_bits::AVX512_VBMI2 | x86_CPUID_7_bits::AVX512_VBITALG;
194 if((flags7 & AVX512_PROFILE_FLAGS) == AVX512_PROFILE_FLAGS) {
195 features_detected |= CPUID::CPUID_AVX512_BIT;
197 if(flags7 & x86_CPUID_7_bits::AVX512_VAES) {
198 features_detected |= CPUID::CPUID_AVX512_AES_BIT;
200 if(flags7 & x86_CPUID_7_bits::AVX512_VCLMUL) {
201 features_detected |= CPUID::CPUID_AVX512_CLMUL_BIT;
211 #if defined(BOTAN_TARGET_ARCH_IS_X86_64)
212 if(features_detected == 0) {
213 features_detected |= CPUID::CPUID_SSE2_BIT;
214 features_detected |= CPUID::CPUID_RDTSC_BIT;
218 return features_detected;
#define BOTAN_FUNC_ISA(isa)
constexpr void clear_mem(T *ptr, size_t n)