]> source.dussan.org Git - rspamd.git/commitdiff
Explicitly test CPU instructions even after CPUID call
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 15 Oct 2015 13:46:43 +0000 (14:46 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 15 Oct 2015 13:46:43 +0000 (14:46 +0100)
src/libcryptobox/cryptobox.c

index 0923905d7f34dba000ff9f38daf25c656b19566e..2ecc707a7594cb3ec6e8b7c7d017059a71a51c63 100644 (file)
@@ -40,6 +40,8 @@
 #include <cpuid.h>
 #endif
 
+#include <signal.h>
+
 unsigned long cpu_config = 0;
 
 static const guchar n0[16] = {0};
@@ -89,6 +91,64 @@ rspamd_cryptobox_cpuid (gint cpu[4], gint info)
 #endif
 }
 
+static sig_atomic_t ok = 0;
+
+static void
+rspamd_cryptobox_ill_handler (int signo)
+{
+       ok = 0;
+}
+
+static gboolean
+rspamd_cryptobox_test_instr (gint instr)
+{
+       void (*old_handler) (int);
+
+#if defined(__GNUC__)
+       ok = 1;
+       old_handler = signal (SIGILL, rspamd_cryptobox_ill_handler);
+
+       switch (instr) {
+#ifdef HAVE_SSE2
+       case CPUID_SSE2:
+               __asm__ volatile ("pmuludq %xmm0, %xmm0");
+               break;
+#endif
+#ifdef HAVE_SSE3
+       case CPUID_SSE3:
+               __asm__ volatile ("movshdup %xmm0, %xmm0");
+               break;
+#endif
+#ifdef HAVE_SSSE3
+       case CPUID_SSSE3:
+               __asm__ volatile ("pshufb %xmm0, %xmm0");
+               break;
+#endif
+#ifdef HAVE_SSE41
+       case CPUID_SSE41:
+               __asm__ volatile ("pcmpeqq %xmm0, %xmm0");
+               break;
+#endif
+#ifdef HAVE_AVX
+       case CPUID_AVX:
+               __asm__ volatile ("vpaddq %xmm0, %xmm0, %xmm0");
+               break;
+#endif
+#ifdef HAVE_AVX2
+       case CPUID_AVX2:
+               __asm__ volatile ("vpaddq %ymm0, %ymm0, %ymm0");\
+               break;
+#endif
+       default:
+               break;
+       }
+
+       signal (SIGILL, old_handler);
+#endif
+
+       return ok == 1;
+}
+
 void
 rspamd_cryptobox_init (void)
 {
@@ -102,25 +162,38 @@ rspamd_cryptobox_init (void)
                /* Check OSXSAVE bit first of all */
                if ((cpu[2] & ((gint)1 << 9))) {
                        if ((cpu[3] & ((gint)1 << 26))) {
-                               cpu_config |= CPUID_SSE2;
+                               if (rspamd_cryptobox_test_instr (CPUID_SSE2)) {
+                                       cpu_config |= CPUID_SSE2;
+                               }
                        }
                        if ((cpu[2] & ((gint)1 << 28))) {
-                               cpu_config |= CPUID_AVX;
+                               if (rspamd_cryptobox_test_instr (CPUID_AVX)) {
+                                       cpu_config |= CPUID_AVX;
+                               }
                        }
                        if ((cpu[2] & ((gint)1 << 0))) {
-                               cpu_config |= CPUID_SSE3;
+                               if (rspamd_cryptobox_test_instr (CPUID_SSE3)) {
+                                       cpu_config |= CPUID_SSE3;
+                               }
                        }
                        if ((cpu[2] & ((gint)1 << 9))) {
-                               cpu_config |= CPUID_SSSE3;
+                               if (rspamd_cryptobox_test_instr (CPUID_SSSE3)) {
+                                       cpu_config |= CPUID_SSSE3;
+                               }
                        }
                        if ((cpu[2] & ((gint)1 << 19))) {
-                               cpu_config |= CPUID_SSE41;
+                               if (rspamd_cryptobox_test_instr (CPUID_SSE41)) {
+                                       cpu_config |= CPUID_SSE41;
+                               }
                        }
 
                        if (nid > 7) {
                                rspamd_cryptobox_cpuid (cpu, 7);
-                               if ((cpu[1] & ((gint)1 <<  5))) {
-                                       cpu_config |= CPUID_AVX2;
+
+                               if ((cpu[1] & ((gint) 1 << 5))) {
+                                       if (rspamd_cryptobox_test_instr (CPUID_AVX2)) {
+                                               cpu_config |= CPUID_AVX2;
+                                       }
                                }
                        }
                }