8#include <botan/internal/cpuid.h>
10#include <botan/compiler.h>
11#include <botan/mem_ops.h>
12#include <botan/internal/target_info.h>
16#if defined(BOTAN_BUILD_COMPILER_IS_MSVC)
24void invoke_cpuid(uint32_t type, uint32_t out[4]) {
27#if defined(BOTAN_USE_GCC_INLINE_ASM)
29 asm volatile(
"cpuid\n\t" :
"=a"(out[0]),
"=b"(out[1]),
"=c"(out[2]),
"=d"(out[3]) :
"0"(type));
31#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC)
32 __cpuid((
int*)out, type);
36 #warning "No way of calling x86 cpuid instruction for this compiler"
40void invoke_cpuid_sublevel(uint32_t type, uint32_t level, uint32_t out[4]) {
43#if defined(BOTAN_USE_GCC_INLINE_ASM)
45 asm volatile(
"cpuid\n\t" :
"=a"(out[0]),
"=b"(out[1]),
"=c"(out[2]),
"=d"(out[3]) :
"0"(type),
"2"(level));
47#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC)
48 __cpuidex((
int*)out, type, level);
52 #warning "No way of calling x86 cpuid instruction for this compiler"
62uint32_t CPUID::CPUID_Data::detect_cpu_features(uint32_t allowed) {
63 enum class x86_CPUID_1_bits : uint64_t {
71 OSXSAVE = (1ULL << 59) | (1ULL << 60),
75 enum class x86_CPUID_7_bits : uint64_t {
79 BMI_1_AND_2 = BMI1 | BMI2,
80 AVX512_F = (1ULL << 16),
81 AVX512_DQ = (1ULL << 17),
82 RDSEED = (1ULL << 18),
84 AVX512_IFMA = (1ULL << 21),
86 AVX512_BW = (1ULL << 30),
87 AVX512_VL = (1ULL << 31),
88 AVX512_VBMI = (1ULL << 33),
89 AVX512_VBMI2 = (1ULL << 38),
91 AVX512_VAES = (1ULL << 41),
92 AVX512_VCLMUL = (1ULL << 42),
93 AVX512_VBITALG = (1ULL << 44),
112 AVX512_F | AVX512_DQ | AVX512_IFMA | AVX512_BW | AVX512_VL | AVX512_VBMI | AVX512_VBMI2 | AVX512_VBITALG,
116 enum class x86_CPUID_7_1_bits : uint64_t {
123 uint32_t cpuid[4] = {0};
124 bool has_os_ymm_support =
false;
125 bool has_os_zmm_support =
false;
128 invoke_cpuid(0, cpuid);
130 const uint32_t max_supported_sublevel = cpuid[0];
132 if(max_supported_sublevel >= 1) {
134 invoke_cpuid(1, cpuid);
135 const uint64_t flags0 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[3];
137 feat |=
if_set(flags0, x86_CPUID_1_bits::RDTSC, CPUFeature::Bit::RDTSC, allowed);
139 feat |=
if_set(flags0, x86_CPUID_1_bits::RDRAND, CPUFeature::Bit::RDRAND, allowed);
141 feat |=
if_set(flags0, x86_CPUID_1_bits::SSE2, CPUFeature::Bit::SSE2, allowed);
143 if(is_set(feat, CPUFeature::Bit::SSE2)) {
144 feat |=
if_set(flags0, x86_CPUID_1_bits::SSSE3, CPUFeature::Bit::SSSE3, allowed);
146 if(is_set(feat, CPUFeature::Bit::SSSE3)) {
147 feat |=
if_set(flags0, x86_CPUID_1_bits::CLMUL, CPUFeature::Bit::CLMUL, allowed);
148 feat |=
if_set(flags0, x86_CPUID_1_bits::AESNI, CPUFeature::Bit::AESNI, allowed);
151 const uint64_t osxsave64 =
static_cast<uint64_t
>(x86_CPUID_1_bits::OSXSAVE);
152 if((flags0 & osxsave64) == osxsave64) {
153 const uint64_t xcr_flags = xgetbv();
154 if((xcr_flags & 0x6) == 0x6) {
155 has_os_ymm_support =
true;
156 has_os_zmm_support = (xcr_flags & 0xE0) == 0xE0;
162 if(max_supported_sublevel >= 7) {
164 invoke_cpuid_sublevel(7, 0, cpuid);
166 const uint64_t flags7 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[1];
169 invoke_cpuid_sublevel(7, 1, cpuid);
170 const uint32_t flags7_1 = cpuid[0];
172 feat |=
if_set(flags7, x86_CPUID_7_bits::RDSEED, CPUFeature::Bit::RDSEED, allowed);
173 feat |=
if_set(flags7, x86_CPUID_7_bits::ADX, CPUFeature::Bit::ADX, allowed);
179 feat |=
if_set(flags7, x86_CPUID_7_bits::BMI_1_AND_2, CPUFeature::Bit::BMI, allowed);
181 if(is_set(feat, CPUFeature::Bit::SSSE3)) {
182 feat |=
if_set(flags7, x86_CPUID_7_bits::SHA, CPUFeature::Bit::SHA, allowed);
183 feat |=
if_set(flags7_1, x86_CPUID_7_1_bits::SM3, CPUFeature::Bit::SM3, allowed);
186 if(has_os_ymm_support) {
187 feat |=
if_set(flags7, x86_CPUID_7_bits::AVX2, CPUFeature::Bit::AVX2, allowed);
189 if(is_set(feat, CPUFeature::Bit::AVX2)) {
190 feat |=
if_set(flags7, x86_CPUID_7_bits::GFNI, CPUFeature::Bit::GFNI, allowed);
191 feat |=
if_set(flags7, x86_CPUID_7_bits::AVX512_VAES, CPUFeature::Bit::AVX2_AES, allowed);
192 feat |=
if_set(flags7, x86_CPUID_7_bits::AVX512_VCLMUL, CPUFeature::Bit::AVX2_CLMUL, allowed);
193 feat |=
if_set(flags7_1, x86_CPUID_7_1_bits::SHA512, CPUFeature::Bit::SHA512, allowed);
194 feat |=
if_set(flags7_1, x86_CPUID_7_1_bits::SM4, CPUFeature::Bit::SM4, allowed);
197 if(has_os_zmm_support) {
198 feat |=
if_set(flags7, x86_CPUID_7_bits::AVX512_PROFILE, CPUFeature::Bit::AVX512, allowed);
200 if(is_set(feat, CPUFeature::Bit::AVX512)) {
201 feat |=
if_set(flags7, x86_CPUID_7_bits::AVX512_VAES, CPUFeature::Bit::AVX512_AES, allowed);
202 feat |=
if_set(flags7, x86_CPUID_7_bits::AVX512_VCLMUL, CPUFeature::Bit::AVX512_CLMUL, allowed);
214#if defined(BOTAN_TARGET_ARCH_IS_X86_64)
216 feat |= CPUFeature::Bit::SSE2 & allowed;
217 feat |= CPUFeature::Bit::RDTSC & allowed;
static uint32_t if_set(uint64_t cpuid, T flag, CPUID::Feature bit, uint32_t allowed)
#define BOTAN_FUNC_ISA(isa)
constexpr void clear_mem(T *ptr, size_t n)