summaryrefslogtreecommitdiffstats
path: root/comm/third_party/botan/src/lib/utils/cpuid
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/botan/src/lib/utils/cpuid')
-rw-r--r--comm/third_party/botan/src/lib/utils/cpuid/cpuid.cpp231
-rw-r--r--comm/third_party/botan/src/lib/utils/cpuid/cpuid.h484
-rw-r--r--comm/third_party/botan/src/lib/utils/cpuid/cpuid_arm.cpp237
-rw-r--r--comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp132
-rw-r--r--comm/third_party/botan/src/lib/utils/cpuid/cpuid_x86.cpp214
-rw-r--r--comm/third_party/botan/src/lib/utils/cpuid/info.txt7
6 files changed, 1305 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/utils/cpuid/cpuid.cpp b/comm/third_party/botan/src/lib/utils/cpuid/cpuid.cpp
new file mode 100644
index 0000000000..e76e12ea8d
--- /dev/null
+++ b/comm/third_party/botan/src/lib/utils/cpuid/cpuid.cpp
@@ -0,0 +1,231 @@
+/*
+* Runtime CPU detection
+* (C) 2009,2010,2013,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/cpuid.h>
+#include <botan/types.h>
+#include <botan/exceptn.h>
+#include <botan/parsing.h>
+#include <ostream>
+
+namespace Botan {
+
+bool CPUID::has_simd_32()
+ {
+#if defined(BOTAN_TARGET_SUPPORTS_SSE2)
+ return CPUID::has_sse2();
+#elif defined(BOTAN_TARGET_SUPPORTS_ALTIVEC)
+ return CPUID::has_altivec();
+#elif defined(BOTAN_TARGET_SUPPORTS_NEON)
+ return CPUID::has_neon();
+#else
+ return true;
+#endif
+ }
+
+//static
+std::string CPUID::to_string()
+ {
+ std::vector<std::string> flags;
+
+#define CPUID_PRINT(flag) do { if(has_##flag()) { flags.push_back(#flag); } } while(0)
+
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+ CPUID_PRINT(sse2);
+ CPUID_PRINT(ssse3);
+ CPUID_PRINT(sse41);
+ CPUID_PRINT(sse42);
+ CPUID_PRINT(avx2);
+ CPUID_PRINT(avx512f);
+ CPUID_PRINT(avx512dq);
+ CPUID_PRINT(avx512bw);
+ CPUID_PRINT(avx512_icelake);
+
+ CPUID_PRINT(rdtsc);
+ CPUID_PRINT(bmi1);
+ CPUID_PRINT(bmi2);
+ CPUID_PRINT(adx);
+
+ CPUID_PRINT(aes_ni);
+ CPUID_PRINT(clmul);
+ CPUID_PRINT(rdrand);
+ CPUID_PRINT(rdseed);
+ CPUID_PRINT(intel_sha);
+ CPUID_PRINT(avx512_aes);
+ CPUID_PRINT(avx512_clmul);
+#endif
+
+#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+ CPUID_PRINT(altivec);
+ CPUID_PRINT(power_crypto);
+ CPUID_PRINT(darn_rng);
+#endif
+
+#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
+ CPUID_PRINT(neon);
+ CPUID_PRINT(arm_sve);
+
+ CPUID_PRINT(arm_sha1);
+ CPUID_PRINT(arm_sha2);
+ CPUID_PRINT(arm_aes);
+ CPUID_PRINT(arm_pmull);
+ CPUID_PRINT(arm_sha2_512);
+ CPUID_PRINT(arm_sha3);
+ CPUID_PRINT(arm_sm3);
+ CPUID_PRINT(arm_sm4);
+#endif
+
+#undef CPUID_PRINT
+
+ return string_join(flags, ' ');
+ }
+
+//static
+void CPUID::print(std::ostream& o)
+ {
+ o << "CPUID flags: " << CPUID::to_string() << "\n";
+ }
+
+//static
+void CPUID::initialize()
+ {
+ state() = CPUID_Data();
+ }
+
+CPUID::CPUID_Data::CPUID_Data()
+ {
+ m_cache_line_size = 0;
+ m_processor_features = 0;
+
+#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \
+ defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
+ defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+
+ m_processor_features = detect_cpu_features(&m_cache_line_size);
+
+#endif
+
+ m_processor_features |= CPUID::CPUID_INITIALIZED_BIT;
+
+ if(m_cache_line_size == 0)
+ m_cache_line_size = BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE;
+
+ m_endian_status = runtime_check_endian();
+ }
+
+//static
+CPUID::Endian_Status CPUID::CPUID_Data::runtime_check_endian()
+ {
+ // Check runtime endian
+ const uint32_t endian32 = 0x01234567;
+ const uint8_t* e8 = reinterpret_cast<const uint8_t*>(&endian32);
+
+ CPUID::Endian_Status endian = CPUID::Endian_Status::Unknown;
+
+ if(e8[0] == 0x01 && e8[1] == 0x23 && e8[2] == 0x45 && e8[3] == 0x67)
+ {
+ endian = CPUID::Endian_Status::Big;
+ }
+ else if(e8[0] == 0x67 && e8[1] == 0x45 && e8[2] == 0x23 && e8[3] == 0x01)
+ {
+ endian = CPUID::Endian_Status::Little;
+ }
+ else
+ {
+ throw Internal_Error("Unexpected endian at runtime, neither big nor little");
+ }
+
+ // If we were compiled with a known endian, verify it matches at runtime
+#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
+ BOTAN_ASSERT(endian == CPUID::Endian_Status::Little, "Build and runtime endian match");
+#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
+ BOTAN_ASSERT(endian == CPUID::Endian_Status::Big, "Build and runtime endian match");
+#endif
+
+ return endian;
+ }
+
+std::vector<Botan::CPUID::CPUID_bits>
+CPUID::bit_from_string(const std::string& tok)
+ {
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+ if(tok == "sse2" || tok == "simd")
+ return {Botan::CPUID::CPUID_SSE2_BIT};
+ if(tok == "ssse3")
+ return {Botan::CPUID::CPUID_SSSE3_BIT};
+ if(tok == "sse41")
+ return {Botan::CPUID::CPUID_SSE41_BIT};
+ if(tok == "sse42")
+ return {Botan::CPUID::CPUID_SSE42_BIT};
+ // aes_ni is the string printed on the console when running "botan cpuid"
+ if(tok == "aesni" || tok == "aes_ni")
+ return {Botan::CPUID::CPUID_AESNI_BIT};
+ if(tok == "clmul")
+ return {Botan::CPUID::CPUID_CLMUL_BIT};
+ if(tok == "avx2")
+ return {Botan::CPUID::CPUID_AVX2_BIT};
+ if(tok == "avx512f")
+ return {Botan::CPUID::CPUID_AVX512F_BIT};
+ if(tok == "avx512_icelake")
+ return {Botan::CPUID::CPUID_AVX512_ICL_BIT};
+ // there were two if statements testing "sha" and "intel_sha" separately; combined
+ if(tok == "sha" || tok=="intel_sha")
+ return {Botan::CPUID::CPUID_SHA_BIT};
+ if(tok == "rdtsc")
+ return {Botan::CPUID::CPUID_RDTSC_BIT};
+ if(tok == "bmi1")
+ return {Botan::CPUID::CPUID_BMI1_BIT};
+ if(tok == "bmi2")
+ return {Botan::CPUID::CPUID_BMI2_BIT};
+ if(tok == "adx")
+ return {Botan::CPUID::CPUID_ADX_BIT};
+ if(tok == "rdrand")
+ return {Botan::CPUID::CPUID_RDRAND_BIT};
+ if(tok == "rdseed")
+ return {Botan::CPUID::CPUID_RDSEED_BIT};
+ if(tok == "avx512_aes")
+ return {Botan::CPUID::CPUID_AVX512_AES_BIT};
+ if(tok == "avx512_clmul")
+ return {Botan::CPUID::CPUID_AVX512_CLMUL_BIT};
+
+#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+ if(tok == "altivec" || tok == "simd")
+ return {Botan::CPUID::CPUID_ALTIVEC_BIT};
+ if(tok == "power_crypto")
+ return {Botan::CPUID::CPUID_POWER_CRYPTO_BIT};
+ if(tok == "darn_rng")
+ return {Botan::CPUID::CPUID_DARN_BIT};
+
+#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
+ if(tok == "neon" || tok == "simd")
+ return {Botan::CPUID::CPUID_ARM_NEON_BIT};
+ if(tok == "arm_sve")
+ return {Botan::CPUID::CPUID_ARM_SVE_BIT};
+ if(tok == "armv8sha1" || tok == "arm_sha1")
+ return {Botan::CPUID::CPUID_ARM_SHA1_BIT};
+ if(tok == "armv8sha2" || tok == "arm_sha2")
+ return {Botan::CPUID::CPUID_ARM_SHA2_BIT};
+ if(tok == "armv8aes" || tok == "arm_aes")
+ return {Botan::CPUID::CPUID_ARM_AES_BIT};
+ if(tok == "armv8pmull" || tok == "arm_pmull")
+ return {Botan::CPUID::CPUID_ARM_PMULL_BIT};
+ if(tok == "armv8sha3" || tok == "arm_sha3")
+ return {Botan::CPUID::CPUID_ARM_SHA3_BIT};
+ if(tok == "armv8sha2_512" || tok == "arm_sha2_512")
+ return {Botan::CPUID::CPUID_ARM_SHA2_512_BIT};
+ if(tok == "armv8sm3" || tok == "arm_sm3")
+ return {Botan::CPUID::CPUID_ARM_SM3_BIT};
+ if(tok == "armv8sm4" || tok == "arm_sm4")
+ return {Botan::CPUID::CPUID_ARM_SM4_BIT};
+
+#else
+ BOTAN_UNUSED(tok);
+#endif
+
+ return {};
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/utils/cpuid/cpuid.h b/comm/third_party/botan/src/lib/utils/cpuid/cpuid.h
new file mode 100644
index 0000000000..04d0bbd191
--- /dev/null
+++ b/comm/third_party/botan/src/lib/utils/cpuid/cpuid.h
@@ -0,0 +1,484 @@
+/*
+* Runtime CPU detection
+* (C) 2009,2010,2013,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_CPUID_H_
+#define BOTAN_CPUID_H_
+
+#include <botan/types.h>
+#include <vector>
+#include <string>
+#include <iosfwd>
+
+BOTAN_FUTURE_INTERNAL_HEADER(cpuid.h)
+
+namespace Botan {
+
+/**
+* A class handling runtime CPU feature detection. It is limited to
+* just the features necessary to implement CPU specific code in Botan,
+* rather than being a general purpose utility.
+*
+* This class supports:
+*
+* - x86 features using CPUID. x86 is also the only processor with
+* accurate cache line detection currently.
+*
+* - PowerPC AltiVec detection on Linux, NetBSD, OpenBSD, and macOS
+*
+* - ARM NEON and crypto extensions detection. On Linux and Android
+* systems which support getauxval, that is used to access CPU
+* feature information. Otherwise a relatively portable but
+* thread-unsafe mechanism involving executing probe functions which
+* catching SIGILL signal is used.
+*/
+class BOTAN_PUBLIC_API(2,1) CPUID final
+ {
+ public:
+ /**
+ * Probe the CPU and see what extensions are supported
+ */
+ static void initialize();
+
+ static bool has_simd_32();
+
+ /**
+ * Deprecated equivalent to
+ * o << "CPUID flags: " << CPUID::to_string() << "\n";
+ */
+ BOTAN_DEPRECATED("Use CPUID::to_string")
+ static void print(std::ostream& o);
+
+ /**
+ * Return a possibly empty string containing list of known CPU
+ * extensions. Each name will be seperated by a space, and the ordering
+ * will be arbitrary. This list only contains values that are useful to
+ * Botan (for example FMA instructions are not checked).
+ *
+ * Example outputs "sse2 ssse3 rdtsc", "neon arm_aes", "altivec"
+ */
+ static std::string to_string();
+
+ /**
+ * Return a best guess of the cache line size
+ */
+ static size_t cache_line_size()
+ {
+ return state().cache_line_size();
+ }
+
+ static bool is_little_endian()
+ {
+#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
+ return true;
+#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
+ return false;
+#else
+ return state().endian_status() == Endian_Status::Little;
+#endif
+ }
+
+ static bool is_big_endian()
+ {
+#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
+ return true;
+#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
+ return false;
+#else
+ return state().endian_status() == Endian_Status::Big;
+#endif
+ }
+
+ enum CPUID_bits : uint64_t {
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+ // These values have no relation to cpuid bitfields
+
+ // SIMD instruction sets
+ CPUID_SSE2_BIT = (1ULL << 0),
+ CPUID_SSSE3_BIT = (1ULL << 1),
+ CPUID_SSE41_BIT = (1ULL << 2),
+ CPUID_SSE42_BIT = (1ULL << 3),
+ CPUID_AVX2_BIT = (1ULL << 4),
+ CPUID_AVX512F_BIT = (1ULL << 5),
+
+ CPUID_AVX512DQ_BIT = (1ULL << 6),
+ CPUID_AVX512BW_BIT = (1ULL << 7),
+
+ // Ice Lake profile: AVX-512 F, DQ, BW, IFMA, VBMI, VBMI2, BITALG
+ CPUID_AVX512_ICL_BIT = (1ULL << 11),
+
+ // Crypto-specific ISAs
+ CPUID_AESNI_BIT = (1ULL << 16),
+ CPUID_CLMUL_BIT = (1ULL << 17),
+ CPUID_RDRAND_BIT = (1ULL << 18),
+ CPUID_RDSEED_BIT = (1ULL << 19),
+ CPUID_SHA_BIT = (1ULL << 20),
+ CPUID_AVX512_AES_BIT = (1ULL << 21),
+ CPUID_AVX512_CLMUL_BIT = (1ULL << 22),
+
+ // Misc useful instructions
+ CPUID_RDTSC_BIT = (1ULL << 48),
+ CPUID_ADX_BIT = (1ULL << 49),
+ CPUID_BMI1_BIT = (1ULL << 50),
+ CPUID_BMI2_BIT = (1ULL << 51),
+#endif
+
+#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+ CPUID_ALTIVEC_BIT = (1ULL << 0),
+ CPUID_POWER_CRYPTO_BIT = (1ULL << 1),
+ CPUID_DARN_BIT = (1ULL << 2),
+#endif
+
+#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
+ CPUID_ARM_NEON_BIT = (1ULL << 0),
+ CPUID_ARM_SVE_BIT = (1ULL << 1),
+ CPUID_ARM_AES_BIT = (1ULL << 16),
+ CPUID_ARM_PMULL_BIT = (1ULL << 17),
+ CPUID_ARM_SHA1_BIT = (1ULL << 18),
+ CPUID_ARM_SHA2_BIT = (1ULL << 19),
+ CPUID_ARM_SHA3_BIT = (1ULL << 20),
+ CPUID_ARM_SHA2_512_BIT = (1ULL << 21),
+ CPUID_ARM_SM3_BIT = (1ULL << 22),
+ CPUID_ARM_SM4_BIT = (1ULL << 23),
+#endif
+
+ CPUID_INITIALIZED_BIT = (1ULL << 63)
+ };
+
+#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+ /**
+ * Check if the processor supports AltiVec/VMX
+ */
+ static bool has_altivec()
+ { return has_cpuid_bit(CPUID_ALTIVEC_BIT); }
+
+ /**
+ * Check if the processor supports POWER8 crypto extensions
+ */
+ static bool has_power_crypto()
+ { return has_cpuid_bit(CPUID_POWER_CRYPTO_BIT); }
+
+ /**
+ * Check if the processor supports POWER9 DARN RNG
+ */
+ static bool has_darn_rng()
+ { return has_cpuid_bit(CPUID_DARN_BIT); }
+
+#endif
+
+#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
+ /**
+ * Check if the processor supports NEON SIMD
+ */
+ static bool has_neon()
+ { return has_cpuid_bit(CPUID_ARM_NEON_BIT); }
+
+ /**
+ * Check if the processor supports ARMv8 SVE
+ */
+ static bool has_arm_sve()
+ { return has_cpuid_bit(CPUID_ARM_SVE_BIT); }
+
+ /**
+ * Check if the processor supports ARMv8 SHA1
+ */
+ static bool has_arm_sha1()
+ { return has_cpuid_bit(CPUID_ARM_SHA1_BIT); }
+
+ /**
+ * Check if the processor supports ARMv8 SHA2
+ */
+ static bool has_arm_sha2()
+ { return has_cpuid_bit(CPUID_ARM_SHA2_BIT); }
+
+ /**
+ * Check if the processor supports ARMv8 AES
+ */
+ static bool has_arm_aes()
+ { return has_cpuid_bit(CPUID_ARM_AES_BIT); }
+
+ /**
+ * Check if the processor supports ARMv8 PMULL
+ */
+ static bool has_arm_pmull()
+ { return has_cpuid_bit(CPUID_ARM_PMULL_BIT); }
+
+ /**
+ * Check if the processor supports ARMv8 SHA-512
+ */
+ static bool has_arm_sha2_512()
+ { return has_cpuid_bit(CPUID_ARM_SHA2_512_BIT); }
+
+ /**
+ * Check if the processor supports ARMv8 SHA-3
+ */
+ static bool has_arm_sha3()
+ { return has_cpuid_bit(CPUID_ARM_SHA3_BIT); }
+
+ /**
+ * Check if the processor supports ARMv8 SM3
+ */
+ static bool has_arm_sm3()
+ { return has_cpuid_bit(CPUID_ARM_SM3_BIT); }
+
+ /**
+ * Check if the processor supports ARMv8 SM4
+ */
+ static bool has_arm_sm4()
+ { return has_cpuid_bit(CPUID_ARM_SM4_BIT); }
+
+#endif
+
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+
+ /**
+ * Check if the processor supports RDTSC
+ */
+ static bool has_rdtsc()
+ { return has_cpuid_bit(CPUID_RDTSC_BIT); }
+
+ /**
+ * Check if the processor supports SSE2
+ */
+ static bool has_sse2()
+ { return has_cpuid_bit(CPUID_SSE2_BIT); }
+
+ /**
+ * Check if the processor supports SSSE3
+ */
+ static bool has_ssse3()
+ { return has_cpuid_bit(CPUID_SSSE3_BIT); }
+
+ /**
+ * Check if the processor supports SSE4.1
+ */
+ static bool has_sse41()
+ { return has_cpuid_bit(CPUID_SSE41_BIT); }
+
+ /**
+ * Check if the processor supports SSE4.2
+ */
+ static bool has_sse42()
+ { return has_cpuid_bit(CPUID_SSE42_BIT); }
+
+ /**
+ * Check if the processor supports AVX2
+ */
+ static bool has_avx2()
+ { return has_cpuid_bit(CPUID_AVX2_BIT); }
+
+ /**
+ * Check if the processor supports AVX-512F
+ */
+ static bool has_avx512f()
+ { return has_cpuid_bit(CPUID_AVX512F_BIT); }
+
+ /**
+ * Check if the processor supports AVX-512DQ
+ */
+ static bool has_avx512dq()
+ { return has_cpuid_bit(CPUID_AVX512DQ_BIT); }
+
+ /**
+ * Check if the processor supports AVX-512BW
+ */
+ static bool has_avx512bw()
+ { return has_cpuid_bit(CPUID_AVX512BW_BIT); }
+
+ /**
+ * Check if the processor supports AVX-512 Ice Lake profile
+ */
+ static bool has_avx512_icelake()
+ { return has_cpuid_bit(CPUID_AVX512_ICL_BIT); }
+
+ /**
+ * Check if the processor supports AVX-512 AES (VAES)
+ */
+ static bool has_avx512_aes()
+ { return has_cpuid_bit(CPUID_AVX512_AES_BIT); }
+
+ /**
+ * Check if the processor supports AVX-512 VPCLMULQDQ
+ */
+ static bool has_avx512_clmul()
+ { return has_cpuid_bit(CPUID_AVX512_CLMUL_BIT); }
+
+ /**
+ * Check if the processor supports BMI1
+ */
+ static bool has_bmi1()
+ { return has_cpuid_bit(CPUID_BMI1_BIT); }
+
+ /**
+ * Check if the processor supports BMI2
+ */
+ static bool has_bmi2()
+ { return has_cpuid_bit(CPUID_BMI2_BIT); }
+
+ /**
+ * Check if the processor supports AES-NI
+ */
+ static bool has_aes_ni()
+ { return has_cpuid_bit(CPUID_AESNI_BIT); }
+
+ /**
+ * Check if the processor supports CLMUL
+ */
+ static bool has_clmul()
+ { return has_cpuid_bit(CPUID_CLMUL_BIT); }
+
+ /**
+ * Check if the processor supports Intel SHA extension
+ */
+ static bool has_intel_sha()
+ { return has_cpuid_bit(CPUID_SHA_BIT); }
+
+ /**
+ * Check if the processor supports ADX extension
+ */
+ static bool has_adx()
+ { return has_cpuid_bit(CPUID_ADX_BIT); }
+
+ /**
+ * Check if the processor supports RDRAND
+ */
+ static bool has_rdrand()
+ { return has_cpuid_bit(CPUID_RDRAND_BIT); }
+
+ /**
+ * Check if the processor supports RDSEED
+ */
+ static bool has_rdseed()
+ { return has_cpuid_bit(CPUID_RDSEED_BIT); }
+#endif
+
+ /**
+ * Check if the processor supports byte-level vector permutes
+ * (SSSE3, NEON, Altivec)
+ */
+ static bool has_vperm()
+ {
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+ return has_ssse3();
+#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
+ return has_neon();
+#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+ return has_altivec();
+#else
+ return false;
+#endif
+ }
+
+ /**
+ * Check if the processor supports hardware AES instructions
+ */
+ static bool has_hw_aes()
+ {
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+ return has_aes_ni();
+#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
+ return has_arm_aes();
+#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+ return has_power_crypto();
+#else
+ return false;
+#endif
+ }
+
+ /**
+ * Check if the processor supports carryless multiply
+ * (CLMUL, PMULL)
+ */
+ static bool has_carryless_multiply()
+ {
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+ return has_clmul();
+#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
+ return has_arm_pmull();
+#elif defined(BOTAN_TARGET_ARCH_IS_PPC64)
+ return has_power_crypto();
+#else
+ return false;
+#endif
+ }
+
+ /*
+ * Clear a CPUID bit
+ * Call CPUID::initialize to reset
+ *
+ * This is only exposed for testing, don't use unless you know
+ * what you are doing.
+ */
+ static void clear_cpuid_bit(CPUID_bits bit)
+ {
+ state().clear_cpuid_bit(static_cast<uint64_t>(bit));
+ }
+
+ /*
+ * Don't call this function, use CPUID::has_xxx above
+ * It is only exposed for the tests.
+ */
+ static bool has_cpuid_bit(CPUID_bits elem)
+ {
+ const uint64_t elem64 = static_cast<uint64_t>(elem);
+ return state().has_bit(elem64);
+ }
+
+ static std::vector<CPUID::CPUID_bits> bit_from_string(const std::string& tok);
+ private:
+ enum class Endian_Status : uint32_t {
+ Unknown = 0x00000000,
+ Big = 0x01234567,
+ Little = 0x67452301,
+ };
+
+ struct CPUID_Data
+ {
+ public:
+ CPUID_Data();
+
+ CPUID_Data(const CPUID_Data& other) = default;
+ CPUID_Data& operator=(const CPUID_Data& other) = default;
+
+ void clear_cpuid_bit(uint64_t bit)
+ {
+ m_processor_features &= ~bit;
+ }
+
+ bool has_bit(uint64_t bit) const
+ {
+ return (m_processor_features & bit) == bit;
+ }
+
+ uint64_t processor_features() const { return m_processor_features; }
+ Endian_Status endian_status() const { return m_endian_status; }
+ size_t cache_line_size() const { return m_cache_line_size; }
+
+ private:
+ static Endian_Status runtime_check_endian();
+
+#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \
+ defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
+ defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+
+ static uint64_t detect_cpu_features(size_t* cache_line_size);
+
+#endif
+ uint64_t m_processor_features;
+ size_t m_cache_line_size;
+ Endian_Status m_endian_status;
+ };
+
+ static CPUID_Data& state()
+ {
+ static CPUID::CPUID_Data g_cpuid;
+ return g_cpuid;
+ }
+ };
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/utils/cpuid/cpuid_arm.cpp b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_arm.cpp
new file mode 100644
index 0000000000..0711dfdf39
--- /dev/null
+++ b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_arm.cpp
@@ -0,0 +1,237 @@
+/*
+* Runtime CPU detection for ARM
+* (C) 2009,2010,2013,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/cpuid.h>
+
+#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
+
+#if defined(BOTAN_TARGET_OS_IS_IOS)
+ #include <sys/types.h>
+ #include <sys/sysctl.h>
+
+#else
+ #include <botan/internal/os_utils.h>
+
+#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
+ #include <sys/auxv.h>
+#endif
+
+#endif
+
+#endif
+
+namespace Botan {
+
+#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
+
+#if defined(BOTAN_TARGET_OS_IS_IOS)
+
+namespace {
+
+uint64_t flags_by_ios_machine_type(const std::string& machine)
+ {
+ /*
+ * This relies on a map of known machine names to features. This
+ * will quickly grow out of date as new products are introduced, but
+ * is apparently the best we can do for iOS.
+ */
+
+ struct version_info {
+ std::string name;
+ size_t min_version_neon;
+ size_t min_version_armv8;
+ };
+
+ static const version_info min_versions[] = {
+ { "iPhone", 2, 6 },
+ { "iPad", 1, 4 },
+ { "iPod", 4, 7 },
+ { "AppleTV", 2, 5 },
+ };
+
+ if(machine.size() < 3)
+ return 0;
+
+ auto comma = machine.find(',');
+
+ // Simulator, or something we don't know about
+ if(comma == std::string::npos)
+ return 0;
+
+ std::string product = machine.substr(0, comma);
+
+ size_t version = 0;
+ size_t place = 1;
+ while(product.size() > 1 && ::isdigit(product.back()))
+ {
+ const size_t digit = product.back() - '0';
+ version += digit * place;
+ place *= 10;
+ product.pop_back();
+ }
+
+ if(version == 0)
+ return 0;
+
+ for(const version_info& info : min_versions)
+ {
+ if(info.name != product)
+ continue;
+
+ if(version >= info.min_version_armv8)
+ {
+ return CPUID::CPUID_ARM_AES_BIT |
+ CPUID::CPUID_ARM_PMULL_BIT |
+ CPUID::CPUID_ARM_SHA1_BIT |
+ CPUID::CPUID_ARM_SHA2_BIT |
+ CPUID::CPUID_ARM_NEON_BIT;
+ }
+
+ if(version >= info.min_version_neon)
+ return CPUID::CPUID_ARM_NEON_BIT;
+ }
+
+ // Some other product we don't know about
+ return 0;
+ }
+
+}
+
+#endif
+
+uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size)
+ {
+ BOTAN_UNUSED(cache_line_size);
+
+ uint64_t detected_features = 0;
+
+#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
+ /*
+ * On systems with getauxval these bits should normally be defined
+ * in bits/auxv.h but some buggy? glibc installs seem to miss them.
+ * These following values are all fixed, for the Linux ELF format,
+ * so we just hardcode them in ARM_hwcap_bit enum.
+ */
+
+ enum ARM_hwcap_bit {
+#if defined(BOTAN_TARGET_ARCH_IS_ARM32)
+ NEON_bit = (1 << 12),
+ AES_bit = (1 << 0),
+ PMULL_bit = (1 << 1),
+ SHA1_bit = (1 << 2),
+ SHA2_bit = (1 << 3),
+
+ ARCH_hwcap_neon = 16, // AT_HWCAP
+ ARCH_hwcap_crypto = 26, // AT_HWCAP2
+#elif defined(BOTAN_TARGET_ARCH_IS_ARM64)
+ NEON_bit = (1 << 1),
+ AES_bit = (1 << 3),
+ PMULL_bit = (1 << 4),
+ SHA1_bit = (1 << 5),
+ SHA2_bit = (1 << 6),
+ SHA3_bit = (1 << 17),
+ SM3_bit = (1 << 18),
+ SM4_bit = (1 << 19),
+ SHA2_512_bit = (1 << 21),
+ SVE_bit = (1 << 22),
+
+ ARCH_hwcap_neon = 16, // AT_HWCAP
+ ARCH_hwcap_crypto = 16, // AT_HWCAP
+#endif
+ };
+
+#if defined(AT_DCACHEBSIZE)
+ // Exists only on Linux
+ const unsigned long dcache_line = OS::get_auxval(AT_DCACHEBSIZE);
+
+ // plausibility check
+ if(dcache_line == 32 || dcache_line == 64 || dcache_line == 128)
+ *cache_line_size = static_cast<size_t>(dcache_line);
+#endif
+
+ const unsigned long hwcap_neon = OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap_neon);
+ if(hwcap_neon & ARM_hwcap_bit::NEON_bit)
+ detected_features |= CPUID::CPUID_ARM_NEON_BIT;
+
+ /*
+ On aarch64 this ends up calling getauxval twice with AT_HWCAP
+ It doesn't seem worth optimizing this out, since getauxval is
+ just reading a field in the ELF header.
+ */
+ const unsigned long hwcap_crypto = OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap_crypto);
+ if(hwcap_crypto & ARM_hwcap_bit::AES_bit)
+ detected_features |= CPUID::CPUID_ARM_AES_BIT;
+ if(hwcap_crypto & ARM_hwcap_bit::PMULL_bit)
+ detected_features |= CPUID::CPUID_ARM_PMULL_BIT;
+ if(hwcap_crypto & ARM_hwcap_bit::SHA1_bit)
+ detected_features |= CPUID::CPUID_ARM_SHA1_BIT;
+ if(hwcap_crypto & ARM_hwcap_bit::SHA2_bit)
+ detected_features |= CPUID::CPUID_ARM_SHA2_BIT;
+
+#if defined(BOTAN_TARGET_ARCH_IS_ARM64)
+ if(hwcap_crypto & ARM_hwcap_bit::SHA3_bit)
+ detected_features |= CPUID::CPUID_ARM_SHA3_BIT;
+ if(hwcap_crypto & ARM_hwcap_bit::SM3_bit)
+ detected_features |= CPUID::CPUID_ARM_SM3_BIT;
+ if(hwcap_crypto & ARM_hwcap_bit::SM4_bit)
+ detected_features |= CPUID::CPUID_ARM_SM4_BIT;
+ if(hwcap_crypto & ARM_hwcap_bit::SHA2_512_bit)
+ detected_features |= CPUID::CPUID_ARM_SHA2_512_BIT;
+ if(hwcap_crypto & ARM_hwcap_bit::SVE_bit)
+ detected_features |= CPUID::CPUID_ARM_SVE_BIT;
+#endif
+
+#elif defined(BOTAN_TARGET_OS_IS_IOS)
+
+ char machine[64] = { 0 };
+ size_t size = sizeof(machine) - 1;
+ ::sysctlbyname("hw.machine", machine, &size, nullptr, 0);
+
+ detected_features = flags_by_ios_machine_type(machine);
+ // No way to detect cache line size on iOS?
+
+#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_ARM64)
+
+ /*
+ No getauxval API available, fall back on probe functions. We only
+ bother with Aarch64 here to simplify the code and because going to
+ extreme contortions to support detect NEON on devices that probably
+ don't support it doesn't seem worthwhile.
+
+ NEON registers v0-v7 are caller saved in Aarch64
+ */
+
+ auto neon_probe = []() noexcept -> int { asm("and v0.16b, v0.16b, v0.16b"); return 1; };
+ auto aes_probe = []() noexcept -> int { asm(".word 0x4e284800"); return 1; };
+ auto pmull_probe = []() noexcept -> int { asm(".word 0x0ee0e000"); return 1; };
+ auto sha1_probe = []() noexcept -> int { asm(".word 0x5e280800"); return 1; };
+ auto sha2_probe = []() noexcept -> int { asm(".word 0x5e282800"); return 1; };
+
+ // Only bother running the crypto detection if we found NEON
+
+ if(OS::run_cpu_instruction_probe(neon_probe) == 1)
+ {
+ detected_features |= CPUID::CPUID_ARM_NEON_BIT;
+
+ if(OS::run_cpu_instruction_probe(aes_probe) == 1)
+ detected_features |= CPUID::CPUID_ARM_AES_BIT;
+ if(OS::run_cpu_instruction_probe(pmull_probe) == 1)
+ detected_features |= CPUID::CPUID_ARM_PMULL_BIT;
+ if(OS::run_cpu_instruction_probe(sha1_probe) == 1)
+ detected_features |= CPUID::CPUID_ARM_SHA1_BIT;
+ if(OS::run_cpu_instruction_probe(sha2_probe) == 1)
+ detected_features |= CPUID::CPUID_ARM_SHA2_BIT;
+ }
+
+#endif
+
+ return detected_features;
+ }
+
+#endif
+
+}
diff --git a/comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp
new file mode 100644
index 0000000000..604b97947c
--- /dev/null
+++ b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp
@@ -0,0 +1,132 @@
+/*
+* Runtime CPU detection for POWER/PowerPC
+* (C) 2009,2010,2013,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/cpuid.h>
+#include <botan/internal/os_utils.h>
+
+#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+
+/*
+* On macOS and OpenBSD ppc, use sysctl to detect AltiVec
+*/
+#if defined(BOTAN_TARGET_OS_IS_MACOS)
+ #include <sys/sysctl.h>
+#elif defined(BOTAN_TARGET_OS_IS_OPENBSD)
+ #include <sys/param.h>
+ #include <sys/sysctl.h>
+ #include <machine/cpu.h>
+#endif
+
+#endif
+
+namespace Botan {
+
+#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+
+/*
+* PowerPC specific block: check for AltiVec using either
+* sysctl or by reading processor version number register.
+*/
+uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size)
+ {
+ BOTAN_UNUSED(cache_line_size);
+
+#if defined(BOTAN_TARGET_OS_IS_MACOS) || defined(BOTAN_TARGET_OS_IS_OPENBSD)
+ // On macOS and OpenBSD, use sysctl
+
+ int sels[2] = {
+#if defined(BOTAN_TARGET_OS_IS_OPENBSD)
+ CTL_MACHDEP, CPU_ALTIVEC
+#else
+ CTL_HW, HW_VECTORUNIT
+#endif
+ };
+
+ int vector_type = 0;
+ size_t length = sizeof(vector_type);
+ int error = ::sysctl(sels, 2, &vector_type, &length, NULL, 0);
+
+ if(error == 0 && vector_type > 0)
+ return CPUID::CPUID_ALTIVEC_BIT;
+
+#elif (defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_HAS_ELF_AUX_INFO)) && defined(BOTAN_TARGET_ARCH_IS_PPC64)
+
+ enum PPC_hwcap_bit {
+ ALTIVEC_bit = (1 << 28),
+ CRYPTO_bit = (1 << 25),
+ DARN_bit = (1 << 21),
+
+ ARCH_hwcap_altivec = 16, // AT_HWCAP
+ ARCH_hwcap_crypto = 26, // AT_HWCAP2
+ };
+
+ uint64_t detected_features = 0;
+
+ const unsigned long hwcap_altivec = OS::get_auxval(PPC_hwcap_bit::ARCH_hwcap_altivec);
+ if(hwcap_altivec & PPC_hwcap_bit::ALTIVEC_bit)
+ detected_features |= CPUID::CPUID_ALTIVEC_BIT;
+
+ const unsigned long hwcap_crypto = OS::get_auxval(PPC_hwcap_bit::ARCH_hwcap_crypto);
+ if(hwcap_crypto & PPC_hwcap_bit::CRYPTO_bit)
+ detected_features |= CPUID::CPUID_POWER_CRYPTO_BIT;
+ if(hwcap_crypto & PPC_hwcap_bit::DARN_bit)
+ detected_features |= CPUID::CPUID_DARN_BIT;
+
+ return detected_features;
+
+#else
+
+ /*
+ On PowerPC, MSR 287 is PVR, the Processor Version Number
+ Normally it is only accessible to ring 0, but Linux and NetBSD
+ (others, too, maybe?) will trap and emulate it for us.
+ */
+
+ int pvr = OS::run_cpu_instruction_probe([]() noexcept -> int {
+ uint32_t pvr = 0;
+ asm volatile("mfspr %0, 287" : "=r" (pvr));
+ // Top 16 bits suffice to identify the model
+ return static_cast<int>(pvr >> 16);
+ });
+
+ if(pvr > 0)
+ {
+ const uint16_t ALTIVEC_PVR[] = {
+ 0x003E, // IBM POWER6
+ 0x003F, // IBM POWER7
+ 0x004A, // IBM POWER7p
+ 0x004B, // IBM POWER8E
+ 0x004C, // IBM POWER8 NVL
+ 0x004D, // IBM POWER8
+ 0x004E, // IBM POWER9
+ 0x000C, // G4-7400
+ 0x0039, // G5 970
+ 0x003C, // G5 970FX
+ 0x0044, // G5 970MP
+ 0x0070, // Cell PPU
+ 0, // end
+ };
+
+ for(size_t i = 0; ALTIVEC_PVR[i]; ++i)
+ {
+ if(pvr == ALTIVEC_PVR[i])
+ return CPUID::CPUID_ALTIVEC_BIT;
+ }
+
+ return 0;
+ }
+
+ // TODO try direct instruction probing
+
+#endif
+
+ return 0;
+ }
+
+#endif
+
+}
diff --git a/comm/third_party/botan/src/lib/utils/cpuid/cpuid_x86.cpp b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_x86.cpp
new file mode 100644
index 0000000000..0595e1a604
--- /dev/null
+++ b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_x86.cpp
@@ -0,0 +1,214 @@
+/*
+* Runtime CPU detection for x86
+* (C) 2009,2010,2013,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/cpuid.h>
+#include <botan/mem_ops.h>
+#include <botan/loadstor.h>
+
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+
+#if defined(BOTAN_BUILD_COMPILER_IS_MSVC)
+ #include <intrin.h>
+#elif defined(BOTAN_BUILD_COMPILER_IS_INTEL)
+ #include <ia32intrin.h>
+#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG)
+ #include <cpuid.h>
+#endif
+
+#endif
+
+namespace Botan {
+
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+
+uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size)
+ {
+#if defined(BOTAN_BUILD_COMPILER_IS_MSVC)
+ #define X86_CPUID(type, out) do { __cpuid((int*)out, type); } while(0)
+ #define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0)
+
+#elif defined(BOTAN_BUILD_COMPILER_IS_INTEL)
+ #define X86_CPUID(type, out) do { __cpuid(out, type); } while(0)
+ #define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0)
+
+#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && defined(BOTAN_USE_GCC_INLINE_ASM)
+ #define X86_CPUID(type, out) \
+ asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \
+ : "0" (type))
+
+ #define X86_CPUID_SUBLEVEL(type, level, out) \
+ asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \
+ : "0" (type), "2" (level))
+
+#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG)
+ #define X86_CPUID(type, out) do { __get_cpuid(type, out, out+1, out+2, out+3); } while(0)
+
+ #define X86_CPUID_SUBLEVEL(type, level, out) \
+ do { __cpuid_count(type, level, out[0], out[1], out[2], out[3]); } while(0)
+#else
+ #warning "No way of calling x86 cpuid instruction for this compiler"
+ #define X86_CPUID(type, out) do { clear_mem(out, 4); } while(0)
+ #define X86_CPUID_SUBLEVEL(type, level, out) do { clear_mem(out, 4); } while(0)
+#endif
+
+ uint64_t features_detected = 0;
+ uint32_t cpuid[4] = { 0 };
+
+ // CPUID 0: vendor identification, max sublevel
+ X86_CPUID(0, cpuid);
+
+ const uint32_t max_supported_sublevel = cpuid[0];
+
+ const uint32_t INTEL_CPUID[3] = { 0x756E6547, 0x6C65746E, 0x49656E69 };
+ const uint32_t AMD_CPUID[3] = { 0x68747541, 0x444D4163, 0x69746E65 };
+ const bool is_intel = same_mem(cpuid + 1, INTEL_CPUID, 3);
+ const bool is_amd = same_mem(cpuid + 1, AMD_CPUID, 3);
+
+ if(max_supported_sublevel >= 1)
+ {
+ // CPUID 1: feature bits
+ X86_CPUID(1, cpuid);
+ const uint64_t flags0 = (static_cast<uint64_t>(cpuid[2]) << 32) | cpuid[3];
+
+ enum x86_CPUID_1_bits : uint64_t {
+ RDTSC = (1ULL << 4),
+ SSE2 = (1ULL << 26),
+ CLMUL = (1ULL << 33),
+ SSSE3 = (1ULL << 41),
+ SSE41 = (1ULL << 51),
+ SSE42 = (1ULL << 52),
+ AESNI = (1ULL << 57),
+ RDRAND = (1ULL << 62)
+ };
+
+ if(flags0 & x86_CPUID_1_bits::RDTSC)
+ features_detected |= CPUID::CPUID_RDTSC_BIT;
+ if(flags0 & x86_CPUID_1_bits::SSE2)
+ features_detected |= CPUID::CPUID_SSE2_BIT;
+ if(flags0 & x86_CPUID_1_bits::CLMUL)
+ features_detected |= CPUID::CPUID_CLMUL_BIT;
+ if(flags0 & x86_CPUID_1_bits::SSSE3)
+ features_detected |= CPUID::CPUID_SSSE3_BIT;
+ if(flags0 & x86_CPUID_1_bits::SSE41)
+ features_detected |= CPUID::CPUID_SSE41_BIT;
+ if(flags0 & x86_CPUID_1_bits::SSE42)
+ features_detected |= CPUID::CPUID_SSE42_BIT;
+ if(flags0 & x86_CPUID_1_bits::AESNI)
+ features_detected |= CPUID::CPUID_AESNI_BIT;
+ if(flags0 & x86_CPUID_1_bits::RDRAND)
+ features_detected |= CPUID::CPUID_RDRAND_BIT;
+ }
+
+ if(is_intel)
+ {
+ // Intel cache line size is in cpuid(1) output
+ *cache_line_size = 8 * get_byte(2, cpuid[1]);
+ }
+ else if(is_amd)
+ {
+ // AMD puts it in vendor zone
+ X86_CPUID(0x80000005, cpuid);
+ *cache_line_size = get_byte(3, cpuid[2]);
+ }
+
+ if(max_supported_sublevel >= 7)
+ {
+ clear_mem(cpuid, 4);
+ X86_CPUID_SUBLEVEL(7, 0, cpuid);
+
+ enum x86_CPUID_7_bits : uint64_t {
+ BMI1 = (1ULL << 3),
+ AVX2 = (1ULL << 5),
+ BMI2 = (1ULL << 8),
+ AVX512_F = (1ULL << 16),
+ AVX512_DQ = (1ULL << 17),
+ RDSEED = (1ULL << 18),
+ ADX = (1ULL << 19),
+ AVX512_IFMA = (1ULL << 21),
+ SHA = (1ULL << 29),
+ AVX512_BW = (1ULL << 30),
+ AVX512_VL = (1ULL << 31),
+ AVX512_VBMI = (1ULL << 33),
+ AVX512_VBMI2 = (1ULL << 38),
+ AVX512_VAES = (1ULL << 41),
+ AVX512_VCLMUL = (1ULL << 42),
+ AVX512_VBITALG = (1ULL << 44),
+ };
+
+ const uint64_t flags7 = (static_cast<uint64_t>(cpuid[2]) << 32) | cpuid[1];
+
+ if(flags7 & x86_CPUID_7_bits::AVX2)
+ features_detected |= CPUID::CPUID_AVX2_BIT;
+ if(flags7 & x86_CPUID_7_bits::BMI1)
+ {
+ features_detected |= CPUID::CPUID_BMI1_BIT;
+ /*
+ We only set the BMI2 bit if BMI1 is also supported, so BMI2
+ code can safely use both extensions. No known processor
+ implements BMI2 but not BMI1.
+ */
+ if(flags7 & x86_CPUID_7_bits::BMI2)
+ features_detected |= CPUID::CPUID_BMI2_BIT;
+ }
+
+ if(flags7 & x86_CPUID_7_bits::AVX512_F)
+ {
+ features_detected |= CPUID::CPUID_AVX512F_BIT;
+
+ if(flags7 & x86_CPUID_7_bits::AVX512_DQ)
+ features_detected |= CPUID::CPUID_AVX512DQ_BIT;
+ if(flags7 & x86_CPUID_7_bits::AVX512_BW)
+ features_detected |= CPUID::CPUID_AVX512BW_BIT;
+
+ const uint64_t ICELAKE_FLAGS =
+ x86_CPUID_7_bits::AVX512_F |
+ x86_CPUID_7_bits::AVX512_DQ |
+ x86_CPUID_7_bits::AVX512_IFMA |
+ x86_CPUID_7_bits::AVX512_BW |
+ x86_CPUID_7_bits::AVX512_VL |
+ x86_CPUID_7_bits::AVX512_VBMI |
+ x86_CPUID_7_bits::AVX512_VBMI2 |
+ x86_CPUID_7_bits::AVX512_VBITALG;
+
+ if((flags7 & ICELAKE_FLAGS) == ICELAKE_FLAGS)
+ features_detected |= CPUID::CPUID_AVX512_ICL_BIT;
+
+ if(flags7 & x86_CPUID_7_bits::AVX512_VAES)
+ features_detected |= CPUID::CPUID_AVX512_AES_BIT;
+ if(flags7 & x86_CPUID_7_bits::AVX512_VCLMUL)
+ features_detected |= CPUID::CPUID_AVX512_CLMUL_BIT;
+ }
+
+ if(flags7 & x86_CPUID_7_bits::RDSEED)
+ features_detected |= CPUID::CPUID_RDSEED_BIT;
+ if(flags7 & x86_CPUID_7_bits::ADX)
+ features_detected |= CPUID::CPUID_ADX_BIT;
+ if(flags7 & x86_CPUID_7_bits::SHA)
+ features_detected |= CPUID::CPUID_SHA_BIT;
+ }
+
+#undef X86_CPUID
+#undef X86_CPUID_SUBLEVEL
+
+ /*
+ * If we don't have access to CPUID, we can still safely assume that
+ * any x86-64 processor has SSE2 and RDTSC
+ */
+#if defined(BOTAN_TARGET_ARCH_IS_X86_64)
+ if(features_detected == 0)
+ {
+ features_detected |= CPUID::CPUID_SSE2_BIT;
+ features_detected |= CPUID::CPUID_RDTSC_BIT;
+ }
+#endif
+
+ return features_detected;
+ }
+
+#endif
+
+}
diff --git a/comm/third_party/botan/src/lib/utils/cpuid/info.txt b/comm/third_party/botan/src/lib/utils/cpuid/info.txt
new file mode 100644
index 0000000000..987d7eae4d
--- /dev/null
+++ b/comm/third_party/botan/src/lib/utils/cpuid/info.txt
@@ -0,0 +1,7 @@
+<defines>
+CPUID -> 20170917
+</defines>
+
+<header:public>
+cpuid.h
+</header:public>