"Fossies" - the Fresh Open Source Software Archive

Member "src/Crypto/cpu.c" (10 Oct 2018, 9449 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cpu.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.20_Source_vs_1.21_Source.

    1 /* cpu.c - written and placed in the public domain by Wei Dai */
    2 
    3 #include "cpu.h"
    4 #include "misc.h"
    5 
    6 #ifndef EXCEPTION_EXECUTE_HANDLER
    7 #define EXCEPTION_EXECUTE_HANDLER 1
    8 #endif
    9 
   10 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
   11 #include <signal.h>
   12 #include <setjmp.h>
   13 #endif
   14 
   15 #ifdef CRYPTOPP_CPUID_AVAILABLE
   16 
   17 #if _MSC_VER >= 1400 && CRYPTOPP_BOOL_X64
   18 
   19 int CpuId(uint32 input, uint32 output[4])
   20 {
   21     __cpuid((int *)output, input);
   22     return 1;
   23 }
   24 
   25 #else
   26 
   27 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
   28 
   29 #if defined(__cplusplus)
   30 extern "C" {
   31 #endif
   32 
   33 typedef void (*SigHandler)(int);
   34 
   35 static jmp_buf s_jmpNoCPUID;
   36 static void SigIllHandlerCPUID(int p)
   37 {
   38     longjmp(s_jmpNoCPUID, 1);
   39 }
   40 
   41 #if !defined (_UEFI) && ((defined(__AES__) && defined(__PCLMUL__)) || defined(__INTEL_COMPILER) || CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE)
   42 
   43 static jmp_buf s_jmpNoAESNI;
   44 static void SigIllHandlerAESNI(int p)
   45 {
   46     longjmp(s_jmpNoAESNI, 1);
   47 }
   48 
   49 #endif
   50 
   51 #if CRYPTOPP_BOOL_X64 == 0
   52 static jmp_buf s_jmpNoSSE2;
   53 static void SigIllHandlerSSE2(int p)
   54 {
   55     longjmp(s_jmpNoSSE2, 1);
   56 }
   57 #endif
   58 
   59 #if defined(__cplusplus)
   60 }
   61 #endif
   62 #endif
   63 
   64 int CpuId(uint32 input, uint32 output[4])
   65 {
   66 #ifdef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
   67 #ifndef _UEFI
   68     __try
   69     {
   70 #endif
   71         __asm
   72         {
   73             mov eax, input
   74             mov ecx, 0
   75             cpuid
   76             mov edi, output
   77             mov [edi], eax
   78             mov [edi+4], ebx
   79             mov [edi+8], ecx
   80             mov [edi+12], edx
   81         }
   82 #ifndef _UEFI
   83      }
   84      __except (EXCEPTION_EXECUTE_HANDLER)
   85     {
   86         return 0;
   87     }
   88 #endif
   89 
   90     // function 0 returns the highest basic function understood in EAX
   91     if(input == 0)
   92         return !!output[0]? 1 : 0;
   93 
   94     return 1;
   95 #else
   96     // longjmp and clobber warnings. Volatile is required.
   97     // http://github.com/weidai11/cryptopp/issues/24
   98     // http://stackoverflow.com/q/7721854
   99     volatile int result = 1;
  100 
  101     SigHandler oldHandler = signal(SIGILL, SigIllHandlerCPUID);
  102     if (oldHandler == SIG_ERR)
  103         result = 0;
  104 
  105     if (setjmp(s_jmpNoCPUID))
  106         result = 0;
  107     else
  108     {
  109         asm volatile
  110         (
  111             // save ebx in case -fPIC is being used
  112             // TODO: this might need an early clobber on EDI.
  113 #if CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
  114             "pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx"
  115 #else
  116             "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
  117 #endif
  118             : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3])
  119             : "a" (input), "c" (0)
  120          );
  121     }
  122 
  123     signal(SIGILL, oldHandler);
  124     return result;
  125 #endif
  126 }
  127 
  128 #endif
  129 
  130 static int TrySSE2()
  131 {
  132 #if CRYPTOPP_BOOL_X64
  133     return 1;
  134 #elif defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) && !defined(_UEFI)
  135     volatile int result = 1;
  136 #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
  137     KFLOATING_SAVE floatingPointState;
  138     if (NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState)))
  139     {
  140 #endif
  141     __try
  142     {
  143 #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
  144         AS2(por xmm0, xmm0)        // executing SSE2 instruction
  145 #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
  146         __m128i x = _mm_setzero_si128();
  147         result = _mm_cvtsi128_si32(x) == 0 ? 1 : 0;
  148 #endif
  149     }
  150     __except (EXCEPTION_EXECUTE_HANDLER)
  151     {
  152         result = 0;
  153     }
  154 #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
  155     KeRestoreFloatingPointState (&floatingPointState);
  156     }
  157     else
  158         return 0;
  159 #endif
  160     return result;
  161 #elif !defined(_UEFI)
  162     // longjmp and clobber warnings. Volatile is required.
  163     // http://github.com/weidai11/cryptopp/issues/24
  164     // http://stackoverflow.com/q/7721854
  165     volatile int result = 1;
  166 
  167     SigHandler oldHandler = signal(SIGILL, SigIllHandlerSSE2);
  168     if (oldHandler == SIG_ERR)
  169         return 0;
  170 
  171     if (setjmp(s_jmpNoSSE2))
  172         result = 1;
  173     else
  174     {
  175 #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
  176         __asm __volatile ("por %xmm0, %xmm0");
  177 #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
  178         __m128i x = _mm_setzero_si128();
  179         result = _mm_cvtsi128_si32(x) == 0? 1 : 0;
  180 #endif
  181     }
  182 
  183     signal(SIGILL, oldHandler);
  184     return result;
  185 #else
  186     return 1;
  187 #endif
  188 }
  189 
  190 static uint64 xgetbv()
  191 {
  192 #if defined(_MSC_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) && !defined(_UEFI)
  193      return _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
  194 #elif defined(__GNUC__) || defined(__clang__)
  195     uint32 eax, edx;
  196     __asm__ __volatile__(".byte 0x0F, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(0));
  197     return ((uint64_t)edx << 32) | eax;
  198 #else
  199     return 0;
  200 #endif
  201 }
  202 
  203 volatile int g_x86DetectionDone = 0;
  204 volatile int g_hasISSE = 0, g_hasSSE2 = 0, g_hasSSSE3 = 0, g_hasMMX = 0, g_hasAESNI = 0, g_hasCLMUL = 0, g_isP4 = 0;
  205 volatile int g_hasAVX = 0, g_hasAVX2 = 0, g_hasBMI2 = 0, g_hasSSE42 = 0, g_hasSSE41 = 0, g_isIntel = 0, g_isAMD = 0;
  206 volatile uint32 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
  207 
  208 VC_INLINE int IsIntel(const uint32 output[4])
  209 {
  210     // This is the "GenuineIntel" string
  211     return (output[1] /*EBX*/ == 0x756e6547) &&
  212     (output[2] /*ECX*/ == 0x6c65746e) &&
  213     (output[3] /*EDX*/ == 0x49656e69);
  214 }
  215 
  216 VC_INLINE int IsAMD(const uint32 output[4])
  217 {
  218     // This is the "AuthenticAMD" string
  219     return (output[1] /*EBX*/ == 0x68747541) &&
  220     (output[2] /*ECX*/ == 0x69746E65) &&
  221     (output[3] /*EDX*/ == 0x444D4163);
  222 }
  223 
  224 #if !defined (_UEFI) && ((defined(__AES__) && defined(__PCLMUL__)) || defined(__INTEL_COMPILER) || CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE)
  225 
  226 static int TryAESNI ()
  227 {
  228     volatile int result = 0;
  229 #ifdef _MSC_VER
  230     __try
  231 #else
  232     SigHandler oldHandler = signal(SIGILL, SigIllHandlerAESNI);
  233     if (oldHandler == SIG_ERR)
  234         return 0;
  235 
  236     if (setjmp(s_jmpNoAESNI))
  237         result = 0;
  238     else
  239 #endif
  240     {
  241         __m128i block, subkey, ciphered;
  242         // perform AES round.
  243         block = _mm_setr_epi32(0x11223344,0x55667788,0x99AABBCC,0xDDEEFF00);
  244         subkey = _mm_setr_epi32(0xA5A5A5A5,0xA5A5A5A5,0x5A5A5A5A,0x5A5A5A5A);
  245         ciphered = _mm_aesenc_si128(block, subkey);
  246 #ifdef _MSC_VER
  247         if (ciphered.m128i_u64[0] == LL(0x2f4654b9485061fa) && ciphered.m128i_u64[1] == LL(0xc8b51f1fe1256f99))
  248 #else
  249         if (((uint64_t*)(&ciphered))[0] == LL(0x2f4654b9485061fa) && ((uint64_t*)(&ciphered))[1] == LL(0xc8b51f1fe1256f99))
  250 #endif
  251             result = 1;
  252     }
  253 #ifdef _MSC_VER
  254     __except (EXCEPTION_EXECUTE_HANDLER)
  255     {
  256         // ignore error if AES-NI not supported
  257     }
  258 #else
  259     signal(SIGILL, oldHandler);
  260 #endif
  261     
  262     return result;
  263 }
  264 
  265 static int Detect_MS_HyperV_AES ()
  266 {
  267     int hasAesNI = 0;
  268     // when Hyper-V is enabled on older versions of Windows Server (i.e. 2008 R2), the AES-NI capability 
  269     // gets masked out for all applications, even running on the host.
  270     // We try to detect Hyper-V virtual CPU and perform a dummy AES-NI operation to check its real presence
  271     uint32 cpuid[4];
  272     char HvProductName[13];
  273 
  274     CpuId(0x40000000, cpuid);
  275     memcpy (HvProductName, &cpuid[1], 12);
  276     HvProductName[12] = 0;
  277     if (_stricmp(HvProductName, "Microsoft Hv") == 0)
  278     {
  279 #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
  280         KFLOATING_SAVE floatingPointState;
  281         if (NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState)))
  282         {
  283 #endif
  284         hasAesNI = TryAESNI ();
  285 
  286 #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
  287         KeRestoreFloatingPointState (&floatingPointState);
  288         }
  289 #endif
  290     }
  291 
  292     return hasAesNI;
  293 }
  294 
  295 #endif
  296 
  297 void DetectX86Features()
  298 {
  299     uint32 cpuid[4] = {0}, cpuid1[4] = {0};
  300     if (!CpuId(0, cpuid))
  301         return;
  302     if (!CpuId(1, cpuid1))
  303         return;
  304 
  305     g_hasMMX = (cpuid1[3] & (1 << 23)) != 0;
  306     if ((cpuid1[3] & (1 << 26)) != 0)
  307         g_hasSSE2 = TrySSE2();
  308     if (g_hasSSE2 && (cpuid1[2] & (1 << 28)) && (cpuid1[2] & (1 << 27)) && (cpuid1[2] & (1 << 26))) /* CPU has AVX and OS supports XSAVE/XRSTORE */
  309     {
  310       uint64 xcrFeatureMask = xgetbv();
  311       g_hasAVX = (xcrFeatureMask & 0x6) == 0x6;
  312     }
  313     g_hasAVX2 = g_hasAVX && (cpuid1[1] & (1 << 5));
  314     g_hasBMI2 = g_hasSSE2 && (cpuid1[1] & (1 << 8));
  315     g_hasSSE42 = g_hasSSE2 && (cpuid1[2] & (1 << 20));
  316     g_hasSSE41 = g_hasSSE2 && (cpuid1[2] & (1 << 19));
  317     g_hasSSSE3 = g_hasSSE2 && (cpuid1[2] & (1<<9));
  318     g_hasAESNI = g_hasSSE2 && (cpuid1[2] & (1<<25));
  319     g_hasCLMUL = g_hasSSE2 && (cpuid1[2] & (1<<1));
  320 
  321 #if !defined (_UEFI) && ((defined(__AES__) && defined(__PCLMUL__)) || defined(__INTEL_COMPILER) || CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE)
  322     // Hypervisor = bit 31 of ECX of CPUID leaf 0x1
  323     // reference: http://artemonsecurity.com/vmde.pdf
  324     if (!g_hasAESNI && (cpuid1[2] & (1<<31)))
  325     {
  326         g_hasAESNI = Detect_MS_HyperV_AES ();
  327     }
  328 #endif
  329 
  330     if ((cpuid1[3] & (1 << 25)) != 0)
  331         g_hasISSE = 1;
  332     else
  333     {
  334         uint32 cpuid2[4];
  335         CpuId(0x080000000, cpuid2);
  336         if (cpuid2[0] >= 0x080000001)
  337         {
  338             CpuId(0x080000001, cpuid2);
  339             g_hasISSE = (cpuid2[3] & (1 << 22)) != 0;
  340         }
  341     }
  342 
  343     if (IsIntel(cpuid))
  344     {
  345         g_isIntel = 1;
  346         g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf;
  347         g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1);
  348     }
  349     else if (IsAMD(cpuid))
  350     {
  351         g_isAMD = 1;
  352         CpuId(0x80000005, cpuid);
  353         g_cacheLineSize = GETBYTE(cpuid[2], 0);
  354     }
  355 
  356     if (!g_cacheLineSize)
  357         g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
  358 
  359     *((volatile int*)&g_x86DetectionDone) = 1;
  360 }
  361 
  362 int is_aes_hw_cpu_supported ()
  363 {
  364     int bHasAESNI = 0;
  365     uint32 cpuid[4];
  366 
  367     if (CpuId(1, cpuid))
  368     {
  369         if (cpuid[2] & (1<<25))
  370             bHasAESNI = 1;
  371 #if !defined (_UEFI) && ((defined(__AES__) && defined(__PCLMUL__)) || defined(__INTEL_COMPILER) || CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE)
  372         // Hypervisor = bit 31 of ECX of CPUID leaf 0x1
  373         // reference: http://artemonsecurity.com/vmde.pdf
  374         if (!bHasAESNI && (cpuid[2] & (1<<31)))
  375         {
  376             bHasAESNI = Detect_MS_HyperV_AES ();
  377         }
  378 #endif
  379     }
  380 
  381     return bHasAESNI;
  382 }
  383 
  384 void DisableCPUExtendedFeatures ()
  385 {
  386     g_hasSSE2 = 0;
  387     g_hasISSE = 0;
  388     g_hasMMX = 0;
  389     g_hasSSE2 = 0;
  390     g_hasISSE = 0;
  391     g_hasMMX = 0;
  392     g_hasAVX = 0;
  393     g_hasAVX2 = 0;
  394     g_hasBMI2 = 0;
  395     g_hasSSE42 = 0;
  396     g_hasSSE41 = 0;
  397     g_hasSSSE3 = 0;
  398     g_hasAESNI = 0;
  399     g_hasCLMUL = 0;
  400 }
  401 
  402 #endif
  403