aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2019-01-31 11:07:38 -0500
committerJack Lloyd <[email protected]>2019-01-31 11:07:38 -0500
commita0837b9a2a21562b4ff289728ed1ca9ca40d20c8 (patch)
tree03ad17b5c146ade50a5524c48ba2f4e6654e7630 /src
parent9cc1d65a35d150ec780dbc6c780dd0dec5fe328c (diff)
parentd9a5ffe01f33d509afac68563dbb26a9dc8b9ef6 (diff)
Merge GH #1821 Refactor CPUID to be thread safe
Diffstat (limited to 'src')
-rw-r--r--src/lib/block/aria/aria.cpp13
-rw-r--r--src/lib/utils/compiler.h9
-rw-r--r--src/lib/utils/cpuid/cpuid.cpp37
-rw-r--r--src/lib/utils/cpuid/cpuid.h72
-rw-r--r--src/lib/utils/cpuid/cpuid_arm.cpp2
-rw-r--r--src/lib/utils/cpuid/cpuid_ppc.cpp2
-rw-r--r--src/lib/utils/cpuid/cpuid_x86.cpp2
-rwxr-xr-xsrc/scripts/ci_build.py2
-rw-r--r--src/tests/test_utils.cpp6
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");