base/dispatch.c, base/dispatch-x86ish.S: Add opcode to `rdrand_works_p'.
[catacomb] / base / dispatch.c
index 7806d40..bda7f88 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "config.h"
 
+#include <assert.h>
 #include <ctype.h>
 #include <stdarg.h>
 #include <stdio.h>
 
 #if CPUFAM_X86 || CPUFAM_AMD64
 
+enum {
+  CPUID_1_D,                           /* eax = 1 => edx&?? */
 #  define CPUID1D_SSE2 (1u << 26)
 #  define CPUID1D_FXSR (1u << 24)
+
+  CPUID_1_C,                           /* eax = 1 => ecx&?? */
 #  define CPUID1C_PCLMUL (1u << 1)
 #  define CPUID1C_SSSE3 (1u << 9)
 #  define CPUID1C_AESNI (1u << 25)
 #  define CPUID1C_AVX (1u << 28)
 #  define CPUID1C_RDRAND (1u << 30)
 
+};
+
 struct cpuid { unsigned a, b, c, d; };
 extern int dispatch_x86ish_cpuid(struct cpuid *, unsigned a, unsigned c);
 extern int dispatch_x86ish_xmmregisters_p(void);
-extern int dispatch_x86ish_rdrand(unsigned *);
+extern int dispatch_x86ish_rdrand(unsigned op, unsigned *);
 
 static void cpuid(struct cpuid *cc, unsigned a, unsigned c)
 {
@@ -69,21 +76,33 @@ static void cpuid(struct cpuid *cc, unsigned a, unsigned c)
 static unsigned cpuid_maxleaf(void)
   { struct cpuid c; cpuid(&c, 0, 0); return (c.a); }
 
-/* --- @cpuid_features_p@ --- *
+/* --- @cpuid_feature_p@ --- *
  *
- * Arguments:  @unsigned dbits@ = bits to check in EDX
- *             @unsigned cbits@ = bits to check in ECX
+ * Arguments:  @unsigned leaf@ = leaf to look up
+ *             @unsigned bits@ = bits to check
  *
- * Returns:    Nonzero if all the requested bits are set in the CPUID result
- *             on leaf 1.
+ * Returns:    Nonzero if all the requested bits are set in the requested
+ *             CPUID result.
  */
 
-static int cpuid_features_p(unsigned dbits, unsigned cbits)
+static int cpuid_feature_p(unsigned leaf, unsigned bits)
 {
   struct cpuid c;
-  if (cpuid_maxleaf() < 1) return (0);
-  cpuid(&c, 1, 0);
-  return ((c.d & dbits) == dbits && (c.c & cbits) == cbits);
+  unsigned r;
+
+  switch (leaf) {
+    case CPUID_1_D:
+      if (cpuid_maxleaf() < 1) return (0);
+      cpuid(&c, 1, 0); r = c.d;
+      break;
+    case CPUID_1_C:
+      if (cpuid_maxleaf() < 1) return (0);
+      cpuid(&c, 1, 0); r = c.c;
+      break;
+    default:
+      assert(!"unknown cpuid leaf");
+  }
+  return ((r&bits) == bits);
 }
 
 /* --- @xmm_registers_available_p@ --- *
@@ -111,28 +130,36 @@ static int xmm_registers_available_p(void)
  *             that it's already been verified to be safe to issue.
  */
 
-static int rdrand_works_p(void)
+enum { OP_RDRAND, OP_RDSEED };
+
+static int rdrand_works_p(unsigned op)
 {
   unsigned ref, x, i;
+  const char *what;
+
+  switch (op) {
+    case OP_RDRAND: what = "RDRAND"; break;
+    default: assert(!"unexpected op");
+  }
 
   /* Check that it doesn't always give the same answer.  Try four times: this
    * will fail with probability %$2^{-128}$% with a truly random generator,
    * which seems fair enough.
    */
-  if (dispatch_x86ish_rdrand(&ref)) goto fail;
+  if (dispatch_x86ish_rdrand(op, &ref)) goto fail;
   for (i = 0; i < 4; i++) {
-    if (dispatch_x86ish_rdrand(&x)) goto fail;
+    if (dispatch_x86ish_rdrand(op, &x)) goto fail;
     if (x != ref) goto not_stuck;
   }
-  dispatch_debug("RDRAND always returns 0x%08x!", ref);
+  dispatch_debug("%s always returns 0x%08x!", what, ref);
   return (0);
 
 not_stuck:
-  dispatch_debug("RDRAND instruction looks plausible");
+  dispatch_debug("%s instruction looks plausible", what);
   return (1);
 
 fail:
-  dispatch_debug("RDRAND instruction fails too often");
+  dispatch_debug("%s instruction fails too often", what);
   return (0);
 }
 
@@ -475,8 +502,7 @@ int cpu_feature_p(int feat)
   int IGNORABLE f;
   IGNORE(f);
 #define CASE_CPUFEAT(feat, ftok, cond) case CPUFEAT_##feat:            \
-  if ((f = feat_debug(ftok, "environment override",                    \
-                     check_env(ftok))) >= 0)                           \
+  if ((f = feat_debug(ftok, "environment override", check_env(ftok))) >= 0) \
     return (f);                                                                \
   else                                                                 \
     return (feat_debug(ftok, "runtime probe", cond));
@@ -484,21 +510,22 @@ int cpu_feature_p(int feat)
   switch (feat) {
 #if CPUFAM_X86 || CPUFAM_AMD64
     CASE_CPUFEAT(X86_SSE2, "x86:sse2",
-                cpuid_features_p(CPUID1D_SSE2, 0) &&
+                cpuid_feature_p(CPUID_1_D, CPUID1D_SSE2) &&
                 xmm_registers_available_p());
     CASE_CPUFEAT(X86_AESNI, "x86:aesni",
-                cpuid_features_p(CPUID1D_SSE2, CPUID1C_AESNI) &&
+                cpuid_feature_p(CPUID_1_D, CPUID1C_AESNI) &&
                 xmm_registers_available_p());
     CASE_CPUFEAT(X86_RDRAND, "x86:rdrand",
-                cpuid_features_p(0, CPUID1C_RDRAND) && rdrand_works_p());
+                cpuid_feature_p(CPUID_1_C, CPUID1C_RDRAND) &&
+                rdrand_works_p(OP_RDRAND));
     CASE_CPUFEAT(X86_AVX, "x86:avx",
-                cpuid_features_p(0, CPUID1C_AVX) &&
+                cpuid_feature_p(CPUID_1_C, CPUID1C_AVX) &&
                 xmm_registers_available_p());
     CASE_CPUFEAT(X86_SSSE3, "x86:ssse3",
-                cpuid_features_p(0, CPUID1C_SSSE3) &&
+                cpuid_feature_p(CPUID_1_C, CPUID1C_SSSE3) &&
                 xmm_registers_available_p());
     CASE_CPUFEAT(X86_PCLMUL, "x86:pclmul",
-                cpuid_features_p(0, CPUID1C_PCLMUL) &&
+                cpuid_feature_p(CPUID_1_C, CPUID1C_PCLMUL) &&
                 xmm_registers_available_p());
 #endif
 #ifdef CAPMAP