aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-09-14 12:39:05 -0400
committerJack Lloyd <[email protected]>2016-09-15 09:23:22 -0400
commitdc5aa5be4d254f9f7e9b68cd265058011462cdaf (patch)
tree5f883c1fd95d00ec2c9a5cacc974f43149cc9505
parentbe4655148cfc8cb048fd53de0965cc5e939c4cbc (diff)
Add cpuid overload to test framework
-rw-r--r--src/lib/block/threefish/threefish.cpp6
-rw-r--r--src/lib/utils/cpuid.cpp29
-rw-r--r--src/lib/utils/cpuid.h114
-rw-r--r--src/tests/data/aead/gcm.vec3
-rw-r--r--src/tests/data/block/aes.vec3
-rw-r--r--src/tests/data/block/idea.vec3
-rw-r--r--src/tests/data/block/noekeon.vec3
-rw-r--r--src/tests/data/block/serpent.vec3
-rw-r--r--src/tests/data/block/threefish.vec3
-rw-r--r--src/tests/data/hash/sha1.vec2
-rw-r--r--src/tests/data/stream/chacha.vec3
-rw-r--r--src/tests/tests.cpp113
-rw-r--r--src/tests/tests.h3
13 files changed, 213 insertions, 75 deletions
diff --git a/src/lib/block/threefish/threefish.cpp b/src/lib/block/threefish/threefish.cpp
index a4c99936c..33b3e25c8 100644
--- a/src/lib/block/threefish/threefish.cpp
+++ b/src/lib/block/threefish/threefish.cpp
@@ -103,7 +103,7 @@ void Threefish_512::encrypt_n(const byte in[], byte out[], size_t blocks) const
BOTAN_ASSERT(m_K.size() == 9, "Key was set");
BOTAN_ASSERT(m_T.size() == 3, "Tweak was set");
-#if defined(BOTAN_HAS_THREEFISH_AVX2)
+#if defined(BOTAN_HAS_THREEFISH_512_AVX2)
if(CPUID::has_avx2())
{
return avx2_encrypt_n(in, out, blocks);
@@ -149,10 +149,10 @@ void Threefish_512::decrypt_n(const byte in[], byte out[], size_t blocks) const
BOTAN_ASSERT(m_K.size() == 9, "Key was set");
BOTAN_ASSERT(m_T.size() == 3, "Tweak was set");
-#if defined(BOTAN_HAS_THREEFISH_AVX2)
+#if defined(BOTAN_HAS_THREEFISH_512_AVX2)
if(CPUID::has_avx2())
{
- return avx2_dencrypt_n(in, out, blocks);
+ return avx2_decrypt_n(in, out, blocks);
}
#endif
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];
};
}
diff --git a/src/tests/data/aead/gcm.vec b/src/tests/data/aead/gcm.vec
index 516e828ec..be8250792 100644
--- a/src/tests/data/aead/gcm.vec
+++ b/src/tests/data/aead/gcm.vec
@@ -1,3 +1,6 @@
+
+#test cpuid aesni ssse3 clmul
+
[AES-128/GCM]
# Nist | Test Case 1
Key = 00000000000000000000000000000000
diff --git a/src/tests/data/block/aes.vec b/src/tests/data/block/aes.vec
index 4e0b7399c..50d9cc469 100644
--- a/src/tests/data/block/aes.vec
+++ b/src/tests/data/block/aes.vec
@@ -1,3 +1,6 @@
+
+#test cpuid aesni ssse3
+
[AES-128]
Key = 000102030405060708090A0B0C0D0E0F
In = 00112233445566778899AABBCCDDEEFF
diff --git a/src/tests/data/block/idea.vec b/src/tests/data/block/idea.vec
index 705d02d68..eee5ef5e9 100644
--- a/src/tests/data/block/idea.vec
+++ b/src/tests/data/block/idea.vec
@@ -1,3 +1,6 @@
+
+#test cpuid sse2
+
[IDEA]
Key = ED1BCC9E9267925F3132BA3A8CF9B764
In = 7409000000000000
diff --git a/src/tests/data/block/noekeon.vec b/src/tests/data/block/noekeon.vec
index 2921301c1..08e7cabf3 100644
--- a/src/tests/data/block/noekeon.vec
+++ b/src/tests/data/block/noekeon.vec
@@ -1,3 +1,6 @@
+
+#cpuid simd32
+
[Noekeon]
Key = 00000000000000000000000000000000
In = 00000000000000000000000000000000
diff --git a/src/tests/data/block/serpent.vec b/src/tests/data/block/serpent.vec
index 623ee6be8..8a40c54b7 100644
--- a/src/tests/data/block/serpent.vec
+++ b/src/tests/data/block/serpent.vec
@@ -1,3 +1,6 @@
+
+#test cpuid simd
+
[Serpent]
Key = 00000000000000000000000000000000
In = D29D576FCEA3A3A7ED9099F29273D78E2D62A890CEA3A3A7ED9099F29273D78ED29D576F315C5C58ED9099F29273D78E2D62A890315C5C58ED9099F29273D78ED29D576FCEA3A3A7126F660D9273D78E2D62A890CEA3A3A7126F660D9273D78ED29D576F315C5C58126F660D9273D78E2D62A890315C5C58126F660D9273D78ED29D576FCEA3A3A7ED9099F26D8C28712D62A890CEA3A3A7ED9099F26D8C2871D29D576F315C5C58ED9099F26D8C28712D62A890315C5C58ED9099F26D8C2871D29D576FCEA3A3A7126F660D6D8C28712D62A890CEA3A3A7126F660D6D8C2871D29D576F315C5C58126F660D6D8C2871
diff --git a/src/tests/data/block/threefish.vec b/src/tests/data/block/threefish.vec
index b4e9d8229..dfaccb7ff 100644
--- a/src/tests/data/block/threefish.vec
+++ b/src/tests/data/block/threefish.vec
@@ -1,3 +1,6 @@
+
+#test cpuid avx2
+
[Threefish-512]
Key = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
In = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/src/tests/data/hash/sha1.vec b/src/tests/data/hash/sha1.vec
index f5fd82340..e86650f30 100644
--- a/src/tests/data/hash/sha1.vec
+++ b/src/tests/data/hash/sha1.vec
@@ -1,3 +1,5 @@
+#test cpuid sse2
+
[SHA-160]
In =
Out = DA39A3EE5E6B4B0D3255BFEF95601890AFD80709
diff --git a/src/tests/data/stream/chacha.vec b/src/tests/data/stream/chacha.vec
index 47d3aa7fe..f7ba701ba 100644
--- a/src/tests/data/stream/chacha.vec
+++ b/src/tests/data/stream/chacha.vec
@@ -1,3 +1,6 @@
+
+#test cpuid sse2
+
[ChaCha(8)]
# Tests got from the original implementation of Daniel J. Bernstein
diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp
index a6f96144c..2913e5445 100644
--- a/src/tests/tests.cpp
+++ b/src/tests/tests.cpp
@@ -527,21 +527,21 @@ Text_Based_Test::Text_Based_Test(const std::string& algo,
std::vector<uint8_t> Text_Based_Test::get_req_bin(const VarMap& vars,
const std::string& key) const
- {
- auto i = vars.find(key);
- if(i == vars.end())
- throw Test_Error("Test missing variable " + key);
+ {
+ auto i = vars.find(key);
+ if(i == vars.end())
+ throw Test_Error("Test missing variable " + key);
- try
- {
- return Botan::hex_decode(i->second);
- }
- catch(std::exception&)
- {
- throw Test_Error("Test invalid hex input '" + i->second + "'" +
- + " for key " + key);
- }
+ try
+ {
+ return Botan::hex_decode(i->second);
+ }
+ catch(std::exception&)
+ {
+ throw Test_Error("Test invalid hex input '" + i->second + "'" +
+ + " for key " + key);
}
+ }
std::string Text_Based_Test::get_opt_str(const VarMap& vars,
const std::string& key, const std::string& def_value) const
@@ -646,9 +646,17 @@ std::string Text_Based_Test::get_next_line()
}
m_cur.reset(new std::ifstream(m_srcs[0]));
+ m_cur_src_name = m_srcs[0];
+
+ // Reinit cpuid on new file if needed
+ if(m_cpu_flags.empty() == false)
+ {
+ m_cpu_flags.clear();
+ Botan::CPUID::initialize();
+ }
if(!m_cur->good())
- throw Test_Error("Could not open input file '" + m_srcs[0]);
+ throw Test_Error("Could not open input file '" + m_cur_src_name);
m_srcs.pop_front();
}
@@ -662,7 +670,12 @@ std::string Text_Based_Test::get_next_line()
continue;
if(line[0] == '#')
- continue;
+ {
+ if(line.compare(0, 6, "#test ") == 0)
+ return line;
+ else
+ continue;
+ }
return line;
}
@@ -685,6 +698,42 @@ std::string strip_ws(const std::string& in)
return in.substr(first_c, last_c - first_c + 1);
}
+std::vector<Botan::CPUID::CPUID_bits> map_cpuid_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 == "aesni")
+ return {Botan::CPUID::CPUID_AESNI_BIT};
+ if(tok == "clmul")
+ return {Botan::CPUID::CPUID_CLMUL_BIT};
+ if(tok == "avx2")
+ return {Botan::CPUID::CPUID_AVX2_BIT};
+#endif
+
+#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+ if(tok == "altivec" || tok == "simd")
+ return {Botan::CPUID::CPUID_ALITVEC_BIT};
+#endif
+
+ return {};
+ }
+
+std::vector<Botan::CPUID::CPUID_bits>
+parse_cpuid_bits(const std::vector<std::string>& tok)
+ {
+ std::vector<Botan::CPUID::CPUID_bits> bits;
+ for(size_t i = 1; i < tok.size(); ++i)
+ {
+ const std::vector<Botan::CPUID::CPUID_bits> more = map_cpuid_string(tok[i]);
+ bits.insert(bits.end(), more.begin(), more.end());
+ }
+
+ return bits;
+ }
+
}
std::vector<Test::Result> Text_Based_Test::run()
@@ -701,6 +750,26 @@ std::vector<Test::Result> Text_Based_Test::run()
if(line.empty()) // EOF
break;
+ if(line.compare(0, 6, "#test ") == 0)
+ {
+ std::vector<std::string> pragma_tokens = Botan::split_on(line.substr(6), ' ');
+
+ if(pragma_tokens.empty())
+ throw Test_Error("Empty pragma found in " + m_cur_src_name);
+
+ if(pragma_tokens[0] != "cpuid")
+ throw Test_Error("Unknown test pragma '" + line + "' in " + m_cur_src_name);
+
+ m_cpu_flags = parse_cpuid_bits(pragma_tokens);
+
+ if(m_cpu_flags.empty())
+ throw Test_Error("Empty cpuid pragma in " + m_cur_src_name);
+
+ continue;
+ }
+ else if(line[0] == '#')
+ throw Test_Error("Unknown test pragma '" + line + "' in " + m_cur_src_name);
+
if(line[0] == '[' && line[line.size()-1] == ']')
{
header = line.substr(1, line.size() - 2);
@@ -736,7 +805,21 @@ std::vector<Test::Result> Text_Based_Test::run()
++test_cnt;
uint64_t start = Test::timestamp();
+
Test::Result result = run_one_test(header, vars);
+ if(m_cpu_flags.size() > 0)
+ {
+ for(auto&& cpuid_bit : m_cpu_flags)
+ {
+ if(Botan::CPUID::has_cpuid_bit(cpuid_bit))
+ {
+ Botan::CPUID::clear_cpuid_bit(cpuid_bit);
+ // now re-run the test
+ result.merge(run_one_test(header, vars));
+ }
+ }
+ Botan::CPUID::initialize();
+ }
result.set_ns_consumed(Test::timestamp() - start);
if(result.tests_failed())
diff --git a/src/tests/tests.h b/src/tests/tests.h
index 39aaf67cd..43b9e0d3a 100644
--- a/src/tests/tests.h
+++ b/src/tests/tests.h
@@ -12,6 +12,7 @@
#include <botan/rng.h>
#include <botan/hex.h>
#include <botan/symkey.h>
+#include <botan/cpuid.h>
#if defined(BOTAN_HAS_BIGINT)
#include <botan/bigint.h>
@@ -442,7 +443,9 @@ class Text_Based_Test : public Test
bool m_first = true;
std::unique_ptr<std::ifstream> m_cur;
+ std::string m_cur_src_name;
std::deque<std::string> m_srcs;
+ std::vector<Botan::CPUID::CPUID_bits> m_cpu_flags;
};
}