diff options
Diffstat (limited to 'src/Crypto/cpu.c')
-rw-r--r-- | src/Crypto/cpu.c | 151 |
1 files changed, 140 insertions, 11 deletions
diff --git a/src/Crypto/cpu.c b/src/Crypto/cpu.c index 3de87069..c358088d 100644 --- a/src/Crypto/cpu.c +++ b/src/Crypto/cpu.c @@ -12,10 +12,6 @@ #include <setjmp.h> #endif -#if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE -#include <emmintrin.h> -#endif - #ifdef CRYPTOPP_CPUID_AVAILABLE #if _MSC_VER >= 1400 && CRYPTOPP_BOOL_X64 @@ -42,6 +38,12 @@ static void SigIllHandlerCPUID(int p) longjmp(s_jmpNoCPUID, 1); } +static jmp_buf s_jmpNoAESNI; +static void SigIllHandlerAESNI(int p) +{ + longjmp(s_jmpNoAESNI, 1); +} + #if CRYPTOPP_BOOL_X64 == 0 static jmp_buf s_jmpNoSSE2; static void SigIllHandlerSSE2(int p) @@ -58,8 +60,10 @@ static void SigIllHandlerSSE2(int p) int CpuId(uint32 input, uint32 output[4]) { #ifdef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY +#ifndef _UEFI __try { +#endif __asm { mov eax, input @@ -71,11 +75,13 @@ int CpuId(uint32 input, uint32 output[4]) mov [edi+8], ecx mov [edi+12], edx } - } - __except (EXCEPTION_EXECUTE_HANDLER) +#ifndef _UEFI + } + __except (EXCEPTION_EXECUTE_HANDLER) { return 0; } +#endif // function 0 returns the highest basic function understood in EAX if(input == 0) @@ -121,22 +127,34 @@ static int TrySSE2() { #if CRYPTOPP_BOOL_X64 return 1; -#elif defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) +#elif defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) && !defined(_UEFI) + volatile int result = 1; +#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) + KFLOATING_SAVE floatingPointState; + if (NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState))) + { +#endif __try { #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE AS2(por xmm0, xmm0) // executing SSE2 instruction #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE __m128i x = _mm_setzero_si128(); - return _mm_cvtsi128_si32(x) == 0 ? 1 : 0; + result = _mm_cvtsi128_si32(x) == 0 ? 1 : 0; #endif } __except (EXCEPTION_EXECUTE_HANDLER) { + result = 0; + } +#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) + KeRestoreFloatingPointState (&floatingPointState); + } + else return 0; - } - return 1; -#else +#endif + return result; +#elif !defined(_UEFI) // longjmp and clobber warnings. Volatile is required. // http://github.com/weidai11/cryptopp/issues/24 // http://stackoverflow.com/q/7721854 @@ -160,11 +178,14 @@ static int TrySSE2() signal(SIGILL, oldHandler); return result; +#else + return 1; #endif } int g_x86DetectionDone = 0; int g_hasISSE = 0, g_hasSSE2 = 0, g_hasSSSE3 = 0, g_hasMMX = 0, g_hasAESNI = 0, g_hasCLMUL = 0, g_isP4 = 0; +int g_hasAVX = 0, g_hasSSE42 = 0, g_hasSSE41 = 0; uint32 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; VC_INLINE int IsIntel(const uint32 output[4]) @@ -183,6 +204,79 @@ VC_INLINE int IsAMD(const uint32 output[4]) (output[3] /*EDX*/ == 0x444D4163); } +#if !defined (_UEFI) && ((defined(__AES__) && defined(__PCLMUL__)) || defined(__INTEL_COMPILER) || CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE) + +static int TryAESNI () +{ + volatile int result = 0; +#ifdef _MSC_VER + __try +#else + SigHandler oldHandler = signal(SIGILL, SigIllHandlerAESNI); + if (oldHandler == SIG_ERR) + return 0; + + if (setjmp(s_jmpNoAESNI)) + result = 0; + else +#endif + { + __m128i block, subkey, ciphered; + // perform AES round. + block = _mm_setr_epi32(0x11223344,0x55667788,0x99AABBCC,0xDDEEFF00); + subkey = _mm_setr_epi32(0xA5A5A5A5,0xA5A5A5A5,0x5A5A5A5A,0x5A5A5A5A); + ciphered = _mm_aesenc_si128(block, subkey); +#ifdef _MSC_VER + if (ciphered.m128i_u64[0] == LL(0x2f4654b9485061fa) && ciphered.m128i_u64[1] == LL(0xc8b51f1fe1256f99)) +#else + if (((uint64_t*)(&ciphered))[0] == LL(0x2f4654b9485061fa) && ((uint64_t*)(&ciphered))[1] == LL(0xc8b51f1fe1256f99)) +#endif + result = 1; + } +#ifdef _MSC_VER + __except (EXCEPTION_EXECUTE_HANDLER) + { + // ignore error if AES-NI not supported + } +#else + signal(SIGILL, oldHandler); +#endif + + return result; +} + +static int Detect_MS_HyperV_AES () +{ + int hasAesNI = 0; + // when Hyper-V is enabled on older versions of Windows Server (i.e. 2008 R2), the AES-NI capability + // gets masked out for all applications, even running on the host. + // We try to detect Hyper-V virtual CPU and perform a dummy AES-NI operation to check its real presence + uint32 cpuid[4]; + char HvProductName[13]; + + CpuId(0x40000000, cpuid); + memcpy (HvProductName, &cpuid[1], 12); + HvProductName[12] = 0; + if (_stricmp(HvProductName, "Microsoft Hv") == 0) + { +#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) + KFLOATING_SAVE floatingPointState; + if (NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState))) + { +#endif + hasAesNI = TryAESNI (); + +#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) + KeRestoreFloatingPointState (&floatingPointState); + } +#endif + } + + return hasAesNI; +} + +#endif + void DetectX86Features() { uint32 cpuid[4], cpuid1[4]; @@ -194,10 +288,22 @@ void DetectX86Features() g_hasMMX = (cpuid1[3] & (1 << 23)) != 0; if ((cpuid1[3] & (1 << 26)) != 0) g_hasSSE2 = TrySSE2(); + g_hasAVX = g_hasSSE2 && (cpuid1[2] & (1 << 28)); + g_hasSSE42 = g_hasSSE2 && (cpuid1[2] & (1 << 20)); + g_hasSSE41 = g_hasSSE2 && (cpuid1[2] & (1 << 19)); g_hasSSSE3 = g_hasSSE2 && (cpuid1[2] & (1<<9)); g_hasAESNI = g_hasSSE2 && (cpuid1[2] & (1<<25)); g_hasCLMUL = g_hasSSE2 && (cpuid1[2] & (1<<1)); +#if !defined (_UEFI) && ((defined(__AES__) && defined(__PCLMUL__)) || defined(__INTEL_COMPILER) || CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE) + // Hypervisor = bit 31 of ECX of CPUID leaf 0x1 + // reference: http://artemonsecurity.com/vmde.pdf + if (!g_hasAESNI && (cpuid1[2] & (1<<31))) + { + g_hasAESNI = Detect_MS_HyperV_AES (); + } +#endif + if ((cpuid1[3] & (1 << 25)) != 0) g_hasISSE = 1; else @@ -228,4 +334,27 @@ void DetectX86Features() *((volatile int*)&g_x86DetectionDone) = 1; } +int is_aes_hw_cpu_supported () +{ + int bHasAESNI = 0; + uint32 cpuid[4]; + + if (CpuId(1, cpuid)) + { + if (cpuid[2] & (1<<25)) + bHasAESNI = 1; +#if !defined (_UEFI) && ((defined(__AES__) && defined(__PCLMUL__)) || defined(__INTEL_COMPILER) || CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE) + // Hypervisor = bit 31 of ECX of CPUID leaf 0x1 + // reference: http://artemonsecurity.com/vmde.pdf + if (!bHasAESNI && (cpuid[2] & (1<<31))) + { + bHasAESNI = Detect_MS_HyperV_AES (); + } +#endif + } + + return bHasAESNI; +} + #endif + |