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)
14 #include <immintrin.h>
17#if defined(BOTAN_BUILD_COMPILER_IS_MSVC)
23#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
27void invoke_cpuid(uint32_t type, uint32_t out[4]) {
30 #if defined(BOTAN_USE_GCC_INLINE_ASM)
31 asm volatile(
"cpuid\n\t" :
"=a"(out[0]),
"=b"(out[1]),
"=c"(out[2]),
"=d"(out[3]) :
"0"(type));
33 #elif defined(BOTAN_BUILD_COMPILER_IS_MSVC)
34 __cpuid((
int*)out, type);
38 #warning "No way of calling x86 cpuid instruction for this compiler"
42void invoke_cpuid_sublevel(uint32_t type, uint32_t level, uint32_t out[4]) {
45 #if defined(BOTAN_USE_GCC_INLINE_ASM)
46 asm volatile(
"cpuid\n\t" :
"=a"(out[0]),
"=b"(out[1]),
"=c"(out[2]),
"=d"(out[3]) :
"0"(type),
"2"(level));
48 #elif defined(BOTAN_BUILD_COMPILER_IS_MSVC)
49 __cpuidex((
int*)out, type, level);
53 #warning "No way of calling x86 cpuid instruction for this compiler"
63uint32_t CPUID::CPUID_Data::detect_cpu_features(uint32_t allowed) {
64 enum class x86_CPUID_1_bits : uint64_t {
72 OSXSAVE = (1ULL << 59) | (1ULL << 60),
76 enum class x86_CPUID_7_bits : uint64_t {
80 BMI_1_AND_2 = BMI1 | BMI2,
81 AVX512_F = (1ULL << 16),
82 AVX512_DQ = (1ULL << 17),
83 RDSEED = (1ULL << 18),
85 AVX512_IFMA = (1ULL << 21),
87 AVX512_BW = (1ULL << 30),
88 AVX512_VL = (1ULL << 31),
89 AVX512_VBMI = (1ULL << 33),
90 AVX512_VBMI2 = (1ULL << 38),
92 AVX512_VAES = (1ULL << 41),
93 AVX512_VCLMUL = (1ULL << 42),
94 AVX512_VBITALG = (1ULL << 44),
113 AVX512_F | AVX512_DQ | AVX512_IFMA | AVX512_BW | AVX512_VL | AVX512_VBMI | AVX512_VBMI2 | AVX512_VBITALG,
117 enum class x86_CPUID_7_1_bits : uint64_t {
124 uint32_t cpuid[4] = {0};
125 bool has_os_ymm_support =
false;
126 bool has_os_zmm_support =
false;
129 invoke_cpuid(0, cpuid);
131 const uint32_t max_supported_sublevel = cpuid[0];
133 if(max_supported_sublevel >= 1) {
135 invoke_cpuid(1, cpuid);
136 const uint64_t flags0 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[3];
138 feat |= if_set(flags0, x86_CPUID_1_bits::RDTSC, CPUID::CPUID_RDTSC_BIT, allowed);
140 feat |= if_set(flags0, x86_CPUID_1_bits::RDRAND, CPUID::CPUID_RDRAND_BIT, allowed);
142 feat |= if_set(flags0, x86_CPUID_1_bits::SSE2, CPUID::CPUID_SSE2_BIT, allowed);
144 if(feat & CPUID::CPUID_SSE2_BIT) {
145 feat |= if_set(flags0, x86_CPUID_1_bits::SSSE3, CPUID::CPUID_SSSE3_BIT, allowed);
147 if(feat & CPUID::CPUID_SSSE3_BIT) {
148 feat |= if_set(flags0, x86_CPUID_1_bits::CLMUL, CPUID::CPUID_CLMUL_BIT, allowed);
149 feat |= if_set(flags0, x86_CPUID_1_bits::AESNI, CPUID::CPUID_AESNI_BIT, allowed);
152 const uint64_t osxsave64 =
static_cast<uint64_t
>(x86_CPUID_1_bits::OSXSAVE);
153 if((flags0 & osxsave64) == osxsave64) {
154 const uint64_t xcr_flags = xgetbv();
155 if((xcr_flags & 0x6) == 0x6) {
156 has_os_ymm_support =
true;
157 has_os_zmm_support = (xcr_flags & 0xE0) == 0xE0;
163 if(max_supported_sublevel >= 7) {
165 invoke_cpuid_sublevel(7, 0, cpuid);
167 const uint64_t flags7 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[1];
170 invoke_cpuid_sublevel(7, 1, cpuid);
171 const uint32_t flags7_1 = cpuid[0];
173 feat |= if_set(flags7, x86_CPUID_7_bits::RDSEED, CPUID::CPUID_RDSEED_BIT, allowed);
174 feat |= if_set(flags7, x86_CPUID_7_bits::ADX, CPUID::CPUID_ADX_BIT, allowed);
180 feat |= if_set(flags7, x86_CPUID_7_bits::BMI_1_AND_2, CPUID::CPUID_BMI_BIT, allowed);
182 if(feat & CPUID::CPUID_SSSE3_BIT) {
183 feat |= if_set(flags7, x86_CPUID_7_bits::SHA, CPUID::CPUID_SHA_BIT, allowed);
184 feat |= if_set(flags7_1, x86_CPUID_7_1_bits::SM3, CPUID::CPUID_SM3_BIT, allowed);
187 if(has_os_ymm_support) {
188 feat |= if_set(flags7, x86_CPUID_7_bits::AVX2, CPUID::CPUID_AVX2_BIT, allowed);
190 if(feat & CPUID::CPUID_AVX2_BIT) {
191 feat |= if_set(flags7, x86_CPUID_7_bits::GFNI, CPUID::CPUID_GFNI_BIT, allowed);
192 feat |= if_set(flags7, x86_CPUID_7_bits::AVX512_VAES, CPUID::CPUID_AVX2_AES_BIT, allowed);
193 feat |= if_set(flags7, x86_CPUID_7_bits::AVX512_VCLMUL, CPUID::CPUID_AVX2_CLMUL_BIT, allowed);
194 feat |= if_set(flags7_1, x86_CPUID_7_1_bits::SHA512, CPUID::CPUID_SHA512_BIT, allowed);
195 feat |= if_set(flags7_1, x86_CPUID_7_1_bits::SM4, CPUID::CPUID_SM4_BIT, allowed);
197 if(has_os_zmm_support) {
198 feat |= if_set(flags7, x86_CPUID_7_bits::AVX512_PROFILE, CPUID::CPUID_AVX512_BIT, allowed);
200 if(feat & CPUID::CPUID_AVX512_BIT) {
201 feat |= if_set(flags7, x86_CPUID_7_bits::AVX512_VAES, CPUID::CPUID_AVX512_AES_BIT, allowed);
202 feat |= if_set(flags7, x86_CPUID_7_bits::AVX512_VCLMUL, CPUID::CPUID_AVX512_CLMUL_BIT, allowed);
213 #if defined(BOTAN_TARGET_ARCH_IS_X86_64)
215 feat |= CPUID::CPUID_SSE2_BIT & allowed;
216 feat |= CPUID::CPUID_RDTSC_BIT & allowed;
#define BOTAN_FUNC_ISA(isa)
constexpr void clear_mem(T *ptr, size_t n)