diff options
Diffstat (limited to 'comm/third_party/botan/src/lib/utils/cpuid/cpuid.cpp')
-rw-r--r-- | comm/third_party/botan/src/lib/utils/cpuid/cpuid.cpp | 231 |
1 files changed, 231 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 {}; + } + +} |