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)
25#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
29void invoke_cpuid(uint32_t type, uint32_t out[4]) {
32 #if defined(BOTAN_USE_GCC_INLINE_ASM)
33 asm volatile(
"cpuid\n\t" :
"=a"(out[0]),
"=b"(out[1]),
"=c"(out[2]),
"=d"(out[3]) :
"0"(type));
35 #elif defined(BOTAN_BUILD_COMPILER_IS_MSVC)
36 __cpuid((
int*)out, type);
39 #warning "No way of calling x86 cpuid instruction for this compiler"
43void invoke_cpuid_sublevel(uint32_t type, uint32_t level, uint32_t out[4]) {
46 #if defined(BOTAN_USE_GCC_INLINE_ASM)
47 asm volatile(
"cpuid\n\t" :
"=a"(out[0]),
"=b"(out[1]),
"=c"(out[2]),
"=d"(out[3]) :
"0"(type),
"2"(level));
49 #elif defined(BOTAN_BUILD_COMPILER_IS_MSVC)
50 __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() {
64 uint32_t features_detected = 0;
65 uint32_t cpuid[4] = {0};
66 bool has_os_ymm_support =
false;
67 bool has_os_zmm_support =
false;
70 invoke_cpuid(0, cpuid);
72 const uint32_t max_supported_sublevel = cpuid[0];
74 if(max_supported_sublevel >= 1) {
76 invoke_cpuid(1, cpuid);
77 const uint64_t flags0 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[3];
79 enum x86_CPUID_1_bits : uint64_t {
85 OSXSAVE = (1ULL << 59),
90 if(flags0 & x86_CPUID_1_bits::RDTSC) {
91 features_detected |= CPUID::CPUID_RDTSC_BIT;
93 if(flags0 & x86_CPUID_1_bits::SSE2) {
94 features_detected |= CPUID::CPUID_SSE2_BIT;
96 if(flags0 & x86_CPUID_1_bits::CLMUL) {
97 features_detected |= CPUID::CPUID_CLMUL_BIT;
99 if(flags0 & x86_CPUID_1_bits::SSSE3) {
100 features_detected |= CPUID::CPUID_SSSE3_BIT;
102 if(flags0 & x86_CPUID_1_bits::AESNI) {
103 features_detected |= CPUID::CPUID_AESNI_BIT;
105 if(flags0 & x86_CPUID_1_bits::RDRAND) {
106 features_detected |= CPUID::CPUID_RDRAND_BIT;
109 if((flags0 & x86_CPUID_1_bits::AVX) && (flags0 & x86_CPUID_1_bits::OSXSAVE)) {
110 const uint64_t xcr_flags = xgetbv();
111 if((xcr_flags & 0x6) == 0x6) {
112 has_os_ymm_support =
true;
113 has_os_zmm_support = (xcr_flags & 0xE0) == 0xE0;
118 if(max_supported_sublevel >= 7) {
120 invoke_cpuid_sublevel(7, 0, cpuid);
122 enum x86_CPUID_7_bits : uint64_t {
126 AVX512_F = (1ULL << 16),
127 AVX512_DQ = (1ULL << 17),
128 RDSEED = (1ULL << 18),
130 AVX512_IFMA = (1ULL << 21),
132 AVX512_BW = (1ULL << 30),
133 AVX512_VL = (1ULL << 31),
134 AVX512_VBMI = (1ULL << 33),
135 AVX512_VBMI2 = (1ULL << 38),
136 AVX512_VAES = (1ULL << 41),
137 AVX512_VCLMUL = (1ULL << 42),
138 AVX512_VBITALG = (1ULL << 44),
141 const uint64_t flags7 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[1];
143 if((flags7 & x86_CPUID_7_bits::AVX2) && has_os_ymm_support) {
144 features_detected |= CPUID::CPUID_AVX2_BIT;
146 if(flags7 & x86_CPUID_7_bits::RDSEED) {
147 features_detected |= CPUID::CPUID_RDSEED_BIT;
149 if(flags7 & x86_CPUID_7_bits::ADX) {
150 features_detected |= CPUID::CPUID_ADX_BIT;
152 if(flags7 & x86_CPUID_7_bits::SHA) {
153 features_detected |= CPUID::CPUID_SHA_BIT;
160 if((flags7 & x86_CPUID_7_bits::BMI1) && (flags7 & x86_CPUID_7_bits::BMI2)) {
161 features_detected |= CPUID::CPUID_BMI_BIT;
164 if((flags7 & x86_CPUID_7_bits::AVX512_F) && has_os_zmm_support) {
165 const uint64_t AVX512_PROFILE_FLAGS = x86_CPUID_7_bits::AVX512_F | x86_CPUID_7_bits::AVX512_DQ |
166 x86_CPUID_7_bits::AVX512_IFMA | x86_CPUID_7_bits::AVX512_BW |
167 x86_CPUID_7_bits::AVX512_VL | x86_CPUID_7_bits::AVX512_VBMI |
168 x86_CPUID_7_bits::AVX512_VBMI2 | x86_CPUID_7_bits::AVX512_VBITALG;
186 if((flags7 & AVX512_PROFILE_FLAGS) == AVX512_PROFILE_FLAGS) {
187 features_detected |= CPUID::CPUID_AVX512_BIT;
189 if(flags7 & x86_CPUID_7_bits::AVX512_VAES) {
190 features_detected |= CPUID::CPUID_AVX512_AES_BIT;
192 if(flags7 & x86_CPUID_7_bits::AVX512_VCLMUL) {
193 features_detected |= CPUID::CPUID_AVX512_CLMUL_BIT;
203 #if defined(BOTAN_TARGET_ARCH_IS_X86_64)
204 if(features_detected == 0) {
205 features_detected |= CPUID::CPUID_SSE2_BIT;
206 features_detected |= CPUID::CPUID_RDTSC_BIT;
210 return features_detected;
#define BOTAN_FUNC_ISA(isa)
constexpr void clear_mem(T *ptr, size_t n)