diff options
author | Jack Lloyd <[email protected]> | 2019-01-31 11:07:38 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2019-01-31 11:07:38 -0500 |
commit | a0837b9a2a21562b4ff289728ed1ca9ca40d20c8 (patch) | |
tree | 03ad17b5c146ade50a5524c48ba2f4e6654e7630 /src | |
parent | 9cc1d65a35d150ec780dbc6c780dd0dec5fe328c (diff) | |
parent | d9a5ffe01f33d509afac68563dbb26a9dc8b9ef6 (diff) |
Merge GH #1821 Refactor CPUID to be thread safe
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/block/aria/aria.cpp | 13 | ||||
-rw-r--r-- | src/lib/utils/compiler.h | 9 | ||||
-rw-r--r-- | src/lib/utils/cpuid/cpuid.cpp | 37 | ||||
-rw-r--r-- | src/lib/utils/cpuid/cpuid.h | 72 | ||||
-rw-r--r-- | src/lib/utils/cpuid/cpuid_arm.cpp | 2 | ||||
-rw-r--r-- | src/lib/utils/cpuid/cpuid_ppc.cpp | 2 | ||||
-rw-r--r-- | src/lib/utils/cpuid/cpuid_x86.cpp | 2 | ||||
-rwxr-xr-x | src/scripts/ci_build.py | 2 | ||||
-rw-r--r-- | src/tests/test_utils.cpp | 6 |
9 files changed, 90 insertions, 55 deletions
diff --git a/src/lib/block/aria/aria.cpp b/src/lib/block/aria/aria.cpp index 2a02330c9..23a8657a1 100644 --- a/src/lib/block/aria/aria.cpp +++ b/src/lib/block/aria/aria.cpp @@ -221,17 +221,18 @@ inline void ARIA_FE(uint32_t& T0, uint32_t& T1, uint32_t& T2, uint32_t& T3) void transform(const uint8_t in[], uint8_t out[], size_t blocks, const secure_vector<uint32_t>& KS) { - // Hit every cache line of S1 and S2 - const size_t cache_line_size = CPUID::cache_line_size(); - /* - * This initializer ensures Z == 0xFFFFFFFF for any cache line size - * in {32,64,128,256,512} + * Hit every cache line of S1, S2, X1, X2 + * + * The initializer of Z ensures Z == 0xFFFFFFFF for any cache line + * size that is a power of 2 and <= 512 */ + const size_t cache_line_size = CPUID::cache_line_size(); + volatile uint32_t Z = 0x11101010; for(size_t i = 0; i < 256; i += cache_line_size / sizeof(uint32_t)) { - Z |= S1[i] | S2[i]; + Z |= S1[i] | S2[i] | X1[i] | X2[i]; } const size_t ROUNDS = (KS.size() / 4) - 1; diff --git a/src/lib/utils/compiler.h b/src/lib/utils/compiler.h index fa8e1cfbf..9dfbd9fa2 100644 --- a/src/lib/utils/compiler.h +++ b/src/lib/utils/compiler.h @@ -131,6 +131,15 @@ #endif /* +* Define BOTAN_THREAD_LOCAL +*/ +#if defined(BOTAN_TARGET_OS_HAS_THREADS) + #define BOTAN_THREAD_LOCAL thread_local +#else + #define BOTAN_THREAD_LOCAL /**/ +#endif + +/* * Define BOTAN_IF_CONSTEXPR */ diff --git a/src/lib/utils/cpuid/cpuid.cpp b/src/lib/utils/cpuid/cpuid.cpp index d2d08dd43..e890af061 100644 --- a/src/lib/utils/cpuid/cpuid.cpp +++ b/src/lib/utils/cpuid/cpuid.cpp @@ -13,9 +13,12 @@ namespace Botan { -uint64_t CPUID::g_processor_features = 0; -size_t CPUID::g_cache_line_size = BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE; -CPUID::Endian_status CPUID::g_endian_status = ENDIAN_UNKNOWN; +//static +CPUID::CPUID_Data& CPUID::state() + { + static BOTAN_THREAD_LOCAL CPUID::CPUID_Data g_cpuid; + return g_cpuid; + } bool CPUID::has_simd_32() { @@ -90,36 +93,44 @@ void CPUID::print(std::ostream& o) //static void CPUID::initialize() { - g_processor_features = 0; + state() = CPUID_Data(); + } +CPUID::CPUID_Data::CPUID_Data() + { #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \ defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \ defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) - g_processor_features = CPUID::detect_cpu_features(&g_cache_line_size); + m_cache_line_size = 0; + m_processor_features = detect_cpu_features(&m_cache_line_size); #endif - g_endian_status = runtime_check_endian(); - g_processor_features |= CPUID::CPUID_INITIALIZED_BIT; + 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::runtime_check_endian() +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); - Endian_status endian = ENDIAN_UNKNOWN; + CPUID::Endian_Status endian = CPUID::Endian_Status::Unknown; if(e8[0] == 0x01 && e8[1] == 0x23 && e8[2] == 0x45 && e8[3] == 0x67) { - endian = ENDIAN_BIG; + endian = CPUID::Endian_Status::Big; } else if(e8[0] == 0x67 && e8[1] == 0x45 && e8[2] == 0x23 && e8[3] == 0x01) { - endian = ENDIAN_LITTLE; + endian = CPUID::Endian_Status::Little; } else { @@ -128,9 +139,9 @@ CPUID::Endian_status CPUID::runtime_check_endian() // If we were compiled with a known endian, verify it matches at runtime #if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) - BOTAN_ASSERT(endian == ENDIAN_LITTLE, "Build and runtime endian match"); + BOTAN_ASSERT(endian == CPUID::Endian_Status::Little, "Build and runtime endian match"); #elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) - BOTAN_ASSERT(endian == ENDIAN_BIG, "Build and runtime endian match"); + BOTAN_ASSERT(endian == CPUID::Endian_Status::Big, "Build and runtime endian match"); #endif return endian; diff --git a/src/lib/utils/cpuid/cpuid.h b/src/lib/utils/cpuid/cpuid.h index 95f6d687b..46eef2095 100644 --- a/src/lib/utils/cpuid/cpuid.h +++ b/src/lib/utils/cpuid/cpuid.h @@ -65,21 +65,17 @@ class BOTAN_PUBLIC_API(2,1) CPUID final */ static size_t cache_line_size() { - if(g_processor_features == 0) - { - initialize(); - } - return g_cache_line_size; + return state().cache_line_size(); } static bool is_little_endian() { - return endian_status() == ENDIAN_LITTLE; + return state().endian_status() == Endian_Status::Little; } static bool is_big_endian() { - return endian_status() == ENDIAN_BIG; + return state().endian_status() == Endian_Status::Big; } enum CPUID_bits : uint64_t { @@ -309,8 +305,7 @@ class BOTAN_PUBLIC_API(2,1) CPUID final */ static void clear_cpuid_bit(CPUID_bits bit) { - const uint64_t mask = ~(static_cast<uint64_t>(bit)); - g_processor_features &= mask; + state().clear_cpuid_bit(static_cast<uint64_t>(bit)); } /* @@ -319,43 +314,56 @@ class BOTAN_PUBLIC_API(2,1) CPUID final */ static bool has_cpuid_bit(CPUID_bits elem) { - if(g_processor_features == 0) - initialize(); - const uint64_t elem64 = static_cast<uint64_t>(elem); - return ((g_processor_features & elem64) == elem64); + return state().has_bit(elem64); } static std::vector<CPUID::CPUID_bits> bit_from_string(const std::string& tok); private: - enum Endian_status : uint32_t { - ENDIAN_UNKNOWN = 0x00000000, - ENDIAN_BIG = 0x01234567, - ENDIAN_LITTLE = 0x67452301, + 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); + 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 Endian_status runtime_check_endian(); - - static Endian_status endian_status() - { - if(g_endian_status == ENDIAN_UNKNOWN) - { - g_endian_status = runtime_check_endian(); - } - return g_endian_status; - } - - static uint64_t g_processor_features; - static size_t g_cache_line_size; - static Endian_status g_endian_status; + static CPUID_Data& state(); }; } diff --git a/src/lib/utils/cpuid/cpuid_arm.cpp b/src/lib/utils/cpuid/cpuid_arm.cpp index beb80f7d0..b5626f96b 100644 --- a/src/lib/utils/cpuid/cpuid_arm.cpp +++ b/src/lib/utils/cpuid/cpuid_arm.cpp @@ -102,7 +102,7 @@ uint64_t flags_by_ios_machine_type(const std::string& machine) #endif -uint64_t CPUID::detect_cpu_features(size_t* cache_line_size) +uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size) { uint64_t detected_features = 0; diff --git a/src/lib/utils/cpuid/cpuid_ppc.cpp b/src/lib/utils/cpuid/cpuid_ppc.cpp index 80a6241df..3afca539c 100644 --- a/src/lib/utils/cpuid/cpuid_ppc.cpp +++ b/src/lib/utils/cpuid/cpuid_ppc.cpp @@ -33,7 +33,7 @@ namespace Botan { * PowerPC specific block: check for AltiVec using either * sysctl or by reading processor version number register. */ -uint64_t CPUID::detect_cpu_features(size_t* cache_line_size) +uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size) { BOTAN_UNUSED(cache_line_size); diff --git a/src/lib/utils/cpuid/cpuid_x86.cpp b/src/lib/utils/cpuid/cpuid_x86.cpp index 5387a801e..97c17da86 100644 --- a/src/lib/utils/cpuid/cpuid_x86.cpp +++ b/src/lib/utils/cpuid/cpuid_x86.cpp @@ -25,7 +25,7 @@ namespace Botan { #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) -uint64_t CPUID::detect_cpu_features(size_t* cache_line_size) +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) diff --git a/src/scripts/ci_build.py b/src/scripts/ci_build.py index c95c9eb56..314ededa5 100755 --- a/src/scripts/ci_build.py +++ b/src/scripts/ci_build.py @@ -53,7 +53,7 @@ def determine_flags(target, target_os, target_cpu, target_cc, cc_bin, ccache, ro 'tls', 'ffi', 'rsa_sign', 'rsa_verify', 'dh_kat', 'ecc_randomized', 'ecdh_kat', 'ecdsa_sign', 'curve25519_scalar', - 'simd_32', 'os_utils', 'util', 'util_dates'] + 'cpuid', 'simd_32', 'os_utils', 'util', 'util_dates'] install_prefix = os.path.join(tempfile.gettempdir(), 'botan-install') flags = ['--prefix=%s' % (install_prefix), diff --git a/src/tests/test_utils.cpp b/src/tests/test_utils.cpp index de9db6683..52d10058b 100644 --- a/src/tests/test_utils.cpp +++ b/src/tests/test_utils.cpp @@ -976,6 +976,12 @@ class CPUID_Tests final : public Test result.test_eq("If endian is big, it is not also little endian", Botan::CPUID::is_little_endian(), false); } + const size_t cache_line_size = Botan::CPUID::cache_line_size(); + + result.test_gte("Cache line size is >= 16", cache_line_size, 16); + result.test_lte("Cache line size is <= 256", cache_line_size, 256); + result.confirm("Cache line size is a power of 2", Botan::is_power_of_2(cache_line_size)); + const std::string cpuid_string = Botan::CPUID::to_string(); result.test_success("CPUID::to_string doesn't crash"); |