diff --git a/cpu.cpp b/cpu.cpp index 8ce4cb13..fba59220 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -319,8 +319,8 @@ void DetectX86Features() // http://community.arm.com/groups/android-community/blog/2014/10/10/runtime-detection-of-cpu-features-on-an-armv8-a-cpu // bool CRYPTOPP_SECTION_INIT g_ArmDetectionDone = false; -bool CRYPTOPP_SECTION_INIT g_hasNEON = false, CRYPTOPP_SECTION_INIT g_hasCRC32 = false, CRYPTOPP_SECTION_INIT g_hasAES = false, CRYPTOPP_SECTION_INIT g_hasSHA1 = false; -bool CRYPTOPP_SECTION_INIT g_hasSHA2 = false; +bool CRYPTOPP_SECTION_INIT g_hasNEON = false, CRYPTOPP_SECTION_INIT g_hasPMULL = false, CRYPTOPP_SECTION_INIT g_hasCRC32 = false; +bool CRYPTOPP_SECTION_INIT g_hasAES = false, CRYPTOPP_SECTION_INIT g_hasSHA1 = false, CRYPTOPP_SECTION_INIT g_hasSHA2 = false; word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY @@ -332,6 +332,12 @@ extern "C" longjmp(s_jmpNoNEON, 1); } + static jmp_buf s_jmpNoPMULL; + static void SigIllHandlerPMULL(int) + { + longjmp(s_jmpNoPMULL, 1); + } + static jmp_buf s_jmpNoCRC32; static void SigIllHandlerCRC32(int) { @@ -426,6 +432,59 @@ static bool TryNEON() #endif // CRYPTOPP_BOOL_NEON_INTRINSICS_AVAILABLE } +static bool TryPMULL() +{ +#if (CRYPTOPP_BOOL_ARM_CRYPTO_INTRINSICS_AVAILABLE) +# if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) + volatile bool result = true; + __try + { + const poly64_t a1={1}, b1={2}; + const poly64x2_t a2={1}, b2={2}; + const poly128_t r1 = vmull_p64(a1, b1); + const poly128_t r2 = vmull_high_p64(a2, b2); + + result = (r1 != r2); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + return result; +# else + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile bool result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerPMULL); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULL, (sigset_t*)&oldMask)) + return false; + + if (setjmp(s_jmpNoPMULL)) + result = false; + else + { + const poly64_t a1={1}, b1={2}; + const poly64x2_t a2={1}, b2={2}; + const poly128_t r1 = vmull_p64(a1, b1); + const poly128_t r2 = vmull_high_p64(a2, b2); + + result = (r1 != r2); + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULL); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // CRYPTOPP_BOOL_CRYPTO_INTRINSICS_AVAILABLE +} + static bool TryCRC32() { #if (CRYPTOPP_BOOL_ARM_CRC32_INTRINSICS_AVAILABLE) @@ -660,6 +719,7 @@ void DetectArmFeatures() #endif { g_hasNEON = TryNEON(); + g_hasPMULL = TryPMULL(); g_hasCRC32 = TryCRC32(); g_hasAES = TryAES(); g_hasSHA1 = TrySHA1(); diff --git a/cpu.h b/cpu.h index 3fe5d4f2..55f1a12b 100644 --- a/cpu.h +++ b/cpu.h @@ -364,7 +364,7 @@ inline int GetCacheLineSize() #elif (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64) extern bool g_ArmDetectionDone; -extern bool g_hasNEON, g_hasCRC32, g_hasAES, g_hasSHA1, g_hasSHA2; +extern bool g_hasNEON, g_hasPMULL, g_hasCRC32, g_hasAES, g_hasSHA1, g_hasSHA2; void CRYPTOPP_API DetectArmFeatures(); //! \brief Determine if an ARM processor has Advanced SIMD available @@ -380,6 +380,19 @@ inline bool HasNEON() return g_hasNEON; } +//! \brief Determine if an ARM processor provides Polynomial Multiplication (long) +//! \returns true if the hardware is capable of polynomial multiplications at runtime, false otherwise. +//! \details The multiplication instructions are available under Aarch64 (ARM-64) and Aarch32 (ARM-32). +//! \details Runtime support requires compile time support. When compiling with GCC, you may +//! need to compile with -march=armv8-a+crypto; while Apple requires +//! -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +inline bool HasPMULL() +{ + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasPMULL; +} + //! \brief Determine if an ARM processor has CRC32 available //! \returns true if the hardware is capable of CRC32 at runtime, false otherwise. //! \details CRC32 instructions provide access to the processor's CRC32 and CRC32-C intructions. @@ -485,20 +498,6 @@ inline int GetCacheLineSize() #else #define CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY -#if defined(CRYPTOPP_LLVM_CLANG_VERSION) || defined(CRYPTOPP_APPLE_CLANG_VERSION) || defined(CRYPTOPP_CLANG_INTEGRATED_ASSEMBLER) - #define NEW_LINE "\n" - #define INTEL_PREFIX ".intel_syntax;" - #define INTEL_NOPREFIX ".intel_syntax;" - #define ATT_PREFIX ".att_syntax;" - #define ATT_NOPREFIX ".att_syntax;" -#else - #define NEW_LINE - #define INTEL_PREFIX ".intel_syntax prefix;" - #define INTEL_NOPREFIX ".intel_syntax noprefix;" - #define ATT_PREFIX ".att_syntax prefix;" - #define ATT_NOPREFIX ".att_syntax noprefix;" -#endif - // define these in two steps to allow arguments to be expanded #define GNU_AS1(x) #x ";" NEW_LINE #define GNU_AS2(x, y) #x ", " #y ";" NEW_LINE @@ -519,21 +518,6 @@ inline int GetCacheLineSize() #define IF0(y) #define IF1(y) y -// Should be confined to GCC, but its used to help manage Clang 3.4 compiler error. -// Also see LLVM Bug 24232, http://llvm.org/bugs/show_bug.cgi?id=24232 . -#ifndef INTEL_PREFIX - #define INTEL_PREFIX -#endif -#ifndef INTEL_NOPREFIX - #define INTEL_NOPREFIX -#endif -#ifndef ATT_PREFIX - #define ATT_PREFIX -#endif -#ifndef ATT_NOPREFIX - #define ATT_NOPREFIX -#endif - #ifdef CRYPTOPP_GENERATE_X64_MASM #define ASM_MOD(x, y) ((x) MOD (y)) #define XMMWORD_PTR XMMWORD PTR @@ -666,6 +650,21 @@ inline int GetCacheLineSize() #endif // X86/X32/X64 +// Applies to both X86/X32/X64 and ARM32/ARM64 +#if defined(CRYPTOPP_LLVM_CLANG_VERSION) || defined(CRYPTOPP_APPLE_CLANG_VERSION) || defined(CRYPTOPP_CLANG_INTEGRATED_ASSEMBLER) + #define NEW_LINE "\n" + #define INTEL_PREFIX ".intel_syntax;" + #define INTEL_NOPREFIX ".intel_syntax;" + #define ATT_PREFIX ".att_syntax;" + #define ATT_NOPREFIX ".att_syntax;" +#else + #define NEW_LINE + #define INTEL_PREFIX ".intel_syntax prefix;" + #define INTEL_NOPREFIX ".intel_syntax noprefix;" + #define ATT_PREFIX ".att_syntax prefix;" + #define ATT_NOPREFIX ".att_syntax noprefix;" +#endif + NAMESPACE_END #endif // CRYPTOPP_CPU_H diff --git a/validat1.cpp b/validat1.cpp index a6115e5e..44e2779f 100644 --- a/validat1.cpp +++ b/validat1.cpp @@ -315,13 +315,14 @@ bool TestSettings() #elif (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64) bool hasNEON = HasNEON(); + bool hasPMULL = HasPMULL(); bool hasCRC32 = HasCRC32(); bool hasAES = HasAES(); bool hasSHA1 = HasSHA1(); bool hasSHA2 = HasSHA2(); cout << "passed: "; - cout << "hasNEON == " << hasNEON << ", hasCRC32 == " << hasCRC32 << ", hasAES == " << hasAES << ", hasSHA1 == " << hasSHA1 << ", hasSHA2 == " << hasSHA2 << endl; + cout << "hasNEON == " << hasNEON << ", hasPMULL == " << hasPMULL << ", hasCRC32 == " << hasCRC32 << ", hasAES == " << hasAES << ", hasSHA1 == " << hasSHA1 << ", hasSHA2 == " << hasSHA2 << endl; #endif if (!pass)