8#include <botan/internal/cpuid.h>
10#include <botan/assert.h>
11#include <botan/mem_ops.h>
12#include <botan/internal/loadstor.h>
13#include <botan/internal/target_info.h>
17#if defined(BOTAN_BUILD_COMPILER_IS_MSVC)
25void invoke_cpuid(uint32_t type, uint32_t out[4]) {
28#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)
44 asm volatile(
"cpuid\n\t" :
"=a"(out[0]),
"=b"(out[1]),
"=c"(out[2]),
"=d"(out[3]) :
"0"(type),
"2"(level));
46#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC)
47 __cpuidex((
int*)out, type, level);
51 #warning "No way of calling x86 cpuid instruction for this compiler"
61uint32_t CPUID::CPUID_Data::detect_cpu_features(uint32_t allowed) {
62 enum class x86_CPUID_1_bits : uint64_t {
70 OSXSAVE = (1ULL << 59) | (1ULL << 60),
74 enum class x86_CPUID_7_bits : uint64_t {
78 BMI_1_AND_2 = BMI1 | BMI2,
79 AVX512_F = (1ULL << 16),
80 AVX512_DQ = (1ULL << 17),
81 RDSEED = (1ULL << 18),
83 AVX512_IFMA = (1ULL << 21),
85 AVX512_BW = (1ULL << 30),
86 AVX512_VL = (1ULL << 31),
87 AVX512_VBMI = (1ULL << 33),
88 AVX512_VBMI2 = (1ULL << 38),
90 AVX512_VAES = (1ULL << 41),
91 AVX512_VCLMUL = (1ULL << 42),
92 AVX512_VBITALG = (1ULL << 44),
111 AVX512_F | AVX512_DQ | AVX512_IFMA | AVX512_BW | AVX512_VL | AVX512_VBMI | AVX512_VBMI2 | AVX512_VBITALG,
115 enum class x86_CPUID_7_1_bits : uint64_t {
122 uint32_t cpuid[4] = {0};
123 bool has_os_ymm_support =
false;
124 bool has_os_zmm_support =
false;
127 invoke_cpuid(0, cpuid);
129 const uint32_t max_supported_sublevel = cpuid[0];
131 if(max_supported_sublevel >= 1) {
133 invoke_cpuid(1, cpuid);
134 const uint64_t flags0 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[3];
136 feat |=
if_set(flags0, x86_CPUID_1_bits::RDTSC, CPUFeature::Bit::RDTSC, allowed);
138 feat |=
if_set(flags0, x86_CPUID_1_bits::RDRAND, CPUFeature::Bit::RDRAND, allowed);
140 feat |=
if_set(flags0, x86_CPUID_1_bits::SSE2, CPUFeature::Bit::SSE2, allowed);
142 if(feat & CPUFeature::Bit::SSE2) {
143 feat |=
if_set(flags0, x86_CPUID_1_bits::SSSE3, CPUFeature::Bit::SSSE3, allowed);
145 if(feat & CPUFeature::Bit::SSSE3) {
146 feat |=
if_set(flags0, x86_CPUID_1_bits::CLMUL, CPUFeature::Bit::CLMUL, allowed);
147 feat |=
if_set(flags0, x86_CPUID_1_bits::AESNI, CPUFeature::Bit::AESNI, allowed);
150 const uint64_t osxsave64 =
static_cast<uint64_t
>(x86_CPUID_1_bits::OSXSAVE);
151 if((flags0 & osxsave64) == osxsave64) {
152 const uint64_t xcr_flags = xgetbv();
153 if((xcr_flags & 0x6) == 0x6) {
154 has_os_ymm_support =
true;
155 has_os_zmm_support = (xcr_flags & 0xE0) == 0xE0;
161 if(max_supported_sublevel >= 7) {
163 invoke_cpuid_sublevel(7, 0, cpuid);
165 const uint64_t flags7 = (
static_cast<uint64_t
>(cpuid[2]) << 32) | cpuid[1];
168 invoke_cpuid_sublevel(7, 1, cpuid);
169 const uint32_t flags7_1 = cpuid[0];
171 feat |=
if_set(flags7, x86_CPUID_7_bits::RDSEED, CPUFeature::Bit::RDSEED, allowed);
172 feat |=
if_set(flags7, x86_CPUID_7_bits::ADX, CPUFeature::Bit::ADX, allowed);
178 feat |=
if_set(flags7, x86_CPUID_7_bits::BMI_1_AND_2, CPUFeature::Bit::BMI, allowed);
180 if(feat & CPUFeature::Bit::SSSE3) {
181 feat |=
if_set(flags7, x86_CPUID_7_bits::SHA, CPUFeature::Bit::SHA, allowed);
182 feat |=
if_set(flags7_1, x86_CPUID_7_1_bits::SM3, CPUFeature::Bit::SM3, allowed);
185 if(has_os_ymm_support) {
186 feat |=
if_set(flags7, x86_CPUID_7_bits::AVX2, CPUFeature::Bit::AVX2, allowed);
188 if(feat & CPUFeature::Bit::AVX2) {
189 feat |=
if_set(flags7, x86_CPUID_7_bits::GFNI, CPUFeature::Bit::GFNI, allowed);
190 feat |=
if_set(flags7, x86_CPUID_7_bits::AVX512_VAES, CPUFeature::Bit::AVX2_AES, allowed);
191 feat |=
if_set(flags7, x86_CPUID_7_bits::AVX512_VCLMUL, CPUFeature::Bit::AVX2_CLMUL, allowed);
192 feat |=
if_set(flags7_1, x86_CPUID_7_1_bits::SHA512, CPUFeature::Bit::SHA512, allowed);
193 feat |=
if_set(flags7_1, x86_CPUID_7_1_bits::SM4, CPUFeature::Bit::SM4, allowed);
195 if(has_os_zmm_support) {
196 feat |=
if_set(flags7, x86_CPUID_7_bits::AVX512_PROFILE, CPUFeature::Bit::AVX512, allowed);
198 if(feat & CPUFeature::Bit::AVX512) {
199 feat |=
if_set(flags7, x86_CPUID_7_bits::AVX512_VAES, CPUFeature::Bit::AVX512_AES, allowed);
200 feat |=
if_set(flags7, x86_CPUID_7_bits::AVX512_VCLMUL, CPUFeature::Bit::AVX512_CLMUL, allowed);
211#if defined(BOTAN_TARGET_ARCH_IS_X86_64)
213 feat |= CPUFeature::Bit::SSE2 & allowed;
214 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)