diff options
Diffstat (limited to 'comm/third_party/botan/src/lib/utils/cpuid/cpuid.h')
-rw-r--r-- | comm/third_party/botan/src/lib/utils/cpuid/cpuid.h | 484 |
1 files changed, 484 insertions, 0 deletions
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 |