aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/utils')
-rw-r--r--src/lib/utils/cpuid.cpp29
-rw-r--r--src/lib/utils/cpuid.h114
2 files changed, 86 insertions, 57 deletions
diff --git a/src/lib/utils/cpuid.cpp b/src/lib/utils/cpuid.cpp
index d3def91ed..3fafadab7 100644
--- a/src/lib/utils/cpuid.cpp
+++ b/src/lib/utils/cpuid.cpp
@@ -73,9 +73,8 @@
namespace Botan {
-u64bit CPUID::g_x86_processor_flags[2] = { 0, 0 };
+u64bit CPUID::g_processor_flags[2] = { 0, 0 };
size_t CPUID::g_cache_line_size = BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE;
-bool CPUID::g_altivec_capable = false;
bool CPUID::g_initialized = false;
namespace {
@@ -173,13 +172,14 @@ void CPUID::print(std::ostream& o)
o << "CPUID flags: ";
#define CPUID_PRINT(flag) do { if(has_##flag()) o << #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(altivec);
CPUID_PRINT(rdtsc);
CPUID_PRINT(bmi2);
@@ -189,18 +189,25 @@ void CPUID::print(std::ostream& o)
CPUID_PRINT(rdseed);
CPUID_PRINT(intel_sha);
CPUID_PRINT(adx);
+#endif
+
+#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+ CPUID_PRINT(altivec);
+#endif
+
#undef CPUID_PRINT
o << "\n";
}
void CPUID::initialize()
{
- if(g_initialized)
- return;
+ clear_mem(g_processor_flags, 2);
#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
- if(altivec_check_sysctl() || altivec_check_pvr_emul())
- g_altivec_capable = true;
+ if(altivec_check_sysctl() || altivec_check_pvr_emul())
+ {
+ g_processor_flags[0] |= CPUID_ALTIVEC_BIT;
+ }
#endif
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
@@ -220,7 +227,7 @@ void CPUID::initialize()
X86_CPUID(1, cpuid);
- g_x86_processor_flags[0] = (static_cast<u64bit>(cpuid[2]) << 32) | cpuid[3];
+ g_processor_flags[0] = (static_cast<u64bit>(cpuid[2]) << 32) | cpuid[3];
if(is_intel)
g_cache_line_size = 8 * get_byte(2, cpuid[1]);
@@ -229,7 +236,7 @@ void CPUID::initialize()
{
clear_mem(cpuid, 4);
X86_CPUID_SUBLEVEL(7, 0, cpuid);
- g_x86_processor_flags[1] = (static_cast<u64bit>(cpuid[2]) << 32) | cpuid[1];
+ g_processor_flags[1] = (static_cast<u64bit>(cpuid[2]) << 32) | cpuid[1];
}
if(is_amd)
@@ -245,8 +252,8 @@ void CPUID::initialize()
* If we don't have access to CPUID, we can still safely assume that
* any x86-64 processor has SSE2 and RDTSC
*/
- if(g_x86_processor_flags[0] == 0)
- g_x86_processor_flags[0] = (1 << CPUID_SSE2_BIT) | (1 << CPUID_RDTSC_BIT);
+ if(g_processor_flags[0] == 0)
+ g_processor_flags[0] = (1 << CPUID_SSE2_BIT) | (1 << CPUID_RDTSC_BIT);
#endif
g_initialized = true;
diff --git a/src/lib/utils/cpuid.h b/src/lib/utils/cpuid.h
index 3781b6f8e..4e276fabe 100644
--- a/src/lib/utils/cpuid.h
+++ b/src/lib/utils/cpuid.h
@@ -15,6 +15,8 @@ namespace Botan {
/**
* A class handling runtime CPU feature detection
+*
+* Currently this class supports only x86 (via CPUID) and PowerPC (AltiVec detection)
*/
class BOTAN_DLL CPUID
{
@@ -24,6 +26,10 @@ class BOTAN_DLL CPUID
*/
static void initialize();
+ static bool has_simd_32();
+
+ static void print(std::ostream& o);
+
/**
* Return a best guess of the cache line size
*/
@@ -36,136 +42,152 @@ class BOTAN_DLL CPUID
return g_cache_line_size;
}
+ enum CPUID_bits {
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+ // This matches the layout of cpuid(1)
+ CPUID_RDTSC_BIT = 4,
+ CPUID_SSE2_BIT = 26,
+ CPUID_CLMUL_BIT = 33,
+ CPUID_SSSE3_BIT = 41,
+ CPUID_SSE41_BIT = 51,
+ CPUID_SSE42_BIT = 52,
+ CPUID_AESNI_BIT = 57,
+ CPUID_RDRAND_BIT = 62,
+
+ CPUID_AVX2_BIT = 64+5,
+ CPUID_BMI2_BIT = 64+8,
+ CPUID_AVX512F_BIT = 64+16,
+ CPUID_RDSEED_BIT = 64+18,
+ CPUID_ADX_BIT = 64+19,
+ CPUID_SHA_BIT = 64+29,
+#endif
+
+#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+ CPUID_ALTIVEC_BIT = 0
+#endif
+
+ // TODO: ARMv8 feature detection
+ };
+
+#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
/**
* Check if the processor supports AltiVec/VMX
*/
static bool has_altivec()
- {
- if(!g_initialized)
- {
- initialize();
- }
+ { return has_cpuid_bit(CPUID_ALTIVEC_BIT); }
+#endif
- return g_altivec_capable;
- }
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
/**
* Check if the processor supports RDTSC
*/
static bool has_rdtsc()
- { return x86_processor_flags_has(CPUID_RDTSC_BIT); }
+ { return has_cpuid_bit(CPUID_RDTSC_BIT); }
/**
* Check if the processor supports SSE2
*/
static bool has_sse2()
- { return x86_processor_flags_has(CPUID_SSE2_BIT); }
+ { return has_cpuid_bit(CPUID_SSE2_BIT); }
/**
* Check if the processor supports SSSE3
*/
static bool has_ssse3()
- { return x86_processor_flags_has(CPUID_SSSE3_BIT); }
+ { return has_cpuid_bit(CPUID_SSSE3_BIT); }
/**
* Check if the processor supports SSE4.1
*/
static bool has_sse41()
- { return x86_processor_flags_has(CPUID_SSE41_BIT); }
+ { return has_cpuid_bit(CPUID_SSE41_BIT); }
/**
* Check if the processor supports SSE4.2
*/
static bool has_sse42()
- { return x86_processor_flags_has(CPUID_SSE42_BIT); }
+ { return has_cpuid_bit(CPUID_SSE42_BIT); }
/**
* Check if the processor supports AVX2
*/
static bool has_avx2()
- { return x86_processor_flags_has(CPUID_AVX2_BIT); }
+ { return has_cpuid_bit(CPUID_AVX2_BIT); }
/**
* Check if the processor supports AVX-512F
*/
static bool has_avx512f()
- { return x86_processor_flags_has(CPUID_AVX512F_BIT); }
+ { return has_cpuid_bit(CPUID_AVX512F_BIT); }
/**
* Check if the processor supports BMI2
*/
static bool has_bmi2()
- { return x86_processor_flags_has(CPUID_BMI2_BIT); }
+ { return has_cpuid_bit(CPUID_BMI2_BIT); }
/**
* Check if the processor supports AES-NI
*/
static bool has_aes_ni()
- { return x86_processor_flags_has(CPUID_AESNI_BIT); }
+ { return has_cpuid_bit(CPUID_AESNI_BIT); }
/**
* Check if the processor supports CLMUL
*/
static bool has_clmul()
- { return x86_processor_flags_has(CPUID_CLMUL_BIT); }
+ { return has_cpuid_bit(CPUID_CLMUL_BIT); }
/**
* Check if the processor supports Intel SHA extension
*/
static bool has_intel_sha()
- { return x86_processor_flags_has(CPUID_SHA_BIT); }
+ { return has_cpuid_bit(CPUID_SHA_BIT); }
/**
* Check if the processor supports ADX extension
*/
static bool has_adx()
- { return x86_processor_flags_has(CPUID_ADX_BIT); }
+ { return has_cpuid_bit(CPUID_ADX_BIT); }
/**
* Check if the processor supports RDRAND
*/
static bool has_rdrand()
- { return x86_processor_flags_has(CPUID_RDRAND_BIT); }
+ { return has_cpuid_bit(CPUID_RDRAND_BIT); }
/**
* Check if the processor supports RDSEED
*/
static bool has_rdseed()
- { return x86_processor_flags_has(CPUID_RDSEED_BIT); }
-
- static bool has_simd_32();
-
- static void print(std::ostream& o);
- private:
- enum CPUID_bits {
- CPUID_RDTSC_BIT = 4,
- CPUID_SSE2_BIT = 26,
- CPUID_CLMUL_BIT = 33,
- CPUID_SSSE3_BIT = 41,
- CPUID_SSE41_BIT = 51,
- CPUID_SSE42_BIT = 52,
- CPUID_AESNI_BIT = 57,
- CPUID_RDRAND_BIT = 62,
+ { return has_cpuid_bit(CPUID_RDSEED_BIT); }
+#endif
- CPUID_AVX2_BIT = 64+5,
- CPUID_BMI2_BIT = 64+8,
- CPUID_AVX512F_BIT = 64+16,
- CPUID_RDSEED_BIT = 64+18,
- CPUID_ADX_BIT = 64+19,
- CPUID_SHA_BIT = 64+29,
- };
+ /*
+ * Clear a CPUID bit
+ * Call CPUID::initialize to reset
+ */
+ static void clear_cpuid_bit(CPUID_bits bit)
+ {
+ BOTAN_ASSERT(bit < 128, "CPUID bit within bounds");
+ const uint64_t mask = ~(static_cast<uint64_t>(1) << (bit % 64));
+ g_processor_flags[bit/64] &= mask;
+ }
- static bool x86_processor_flags_has(u64bit bit)
+ static bool has_cpuid_bit(CPUID_bits elem)
{
if(!g_initialized)
initialize();
- return ((g_x86_processor_flags[bit/64] >> (bit % 64)) & 1);
+ const size_t bit = static_cast<size_t>(elem);
+ BOTAN_ASSERT(bit < 128, "CPUID bit within bounds");
+ return ((g_processor_flags[bit/64] >> (bit % 64)) & 1);
}
+ private:
static bool g_initialized;
- static u64bit g_x86_processor_flags[2];
static size_t g_cache_line_size;
- static bool g_altivec_capable;
+ static u64bit g_processor_flags[2];
};
}