base/dispatch.c, rand/rand.c, and asm: Support `rdseed' for quick noise.
authorMark Wooding <mdw@distorted.org.uk>
Mon, 6 Apr 2020 00:07:41 +0000 (00:07 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 9 May 2020 19:59:28 +0000 (20:59 +0100)
Prefer the `rdseed' instruction over `rdrand' for quick randomness, if
it's available.

base/dispatch-x86ish.S
base/dispatch.c
base/dispatch.h
debian/catacomb2.symbols
rand/rand-x86ish.S
rand/rand.c

index b3b6d1c..57d8d32 100644 (file)
@@ -158,10 +158,11 @@ ENDFUNC
 /// Checking `rdrand'.
 
 FUNC(dispatch_x86ish_rdrand)
 /// Checking `rdrand'.
 
 FUNC(dispatch_x86ish_rdrand)
-       // Enter with two arguments: a code OP requesting `rdrand' (0), and a
-       // pointer X_OUT to a 32-bit word.  Try to generate a random word
-       // using the requested instruction.  If successful, set *X_OUT to the
-       // generated word, and return zero; otherwise, return -1.
+       // Enter with two arguments: a code OP requesting either `rdrand' (0)
+       // or `rdseed' (1), and a pointer X_OUT to a 32-bit word.  Try to
+       // generate a random word using the requested instruction'.  If
+       // successful, set *X_OUT to the generated word, and return zero;
+       // otherwise, return -1.
 
 #if CPUFAM_X86
 #  define OP eax
 
 #if CPUFAM_X86
 #  define OP eax
@@ -182,13 +183,22 @@ FUNC(dispatch_x86ish_rdrand)
 #endif
   endprologue
 
 #endif
   endprologue
 
+       cmp     OP, 0
        mov     COUNT, 16               // fairly persistent
        mov     COUNT, 16               // fairly persistent
+       jne     1f
+
 0:     rdrand  eax
        jc      9f
        dec     COUNT
        jnz     0b
        jmp     8f
 
 0:     rdrand  eax
        jc      9f
        dec     COUNT
        jnz     0b
        jmp     8f
 
+1:     rdseed  eax
+       jc      9f
+       dec     COUNT
+       jnz     1b
+       jmp     8f
+
        // Failed to come up with a random value.
 8:     mov     eax, -1
        ret
        // Failed to come up with a random value.
 8:     mov     eax, -1
        ret
index bda7f88..50c842e 100644 (file)
@@ -56,6 +56,8 @@ enum {
 #  define CPUID1C_AVX (1u << 28)
 #  define CPUID1C_RDRAND (1u << 30)
 
 #  define CPUID1C_AVX (1u << 28)
 #  define CPUID1C_RDRAND (1u << 30)
 
+  CPUID_7_0_B,                         /* eax = 7, ecx = 0 => ebx&?? */
+#  define CPUID70B_RDSEED (1u << 18)
 };
 
 struct cpuid { unsigned a, b, c, d; };
 };
 
 struct cpuid { unsigned a, b, c, d; };
@@ -99,6 +101,10 @@ static int cpuid_feature_p(unsigned leaf, unsigned bits)
       if (cpuid_maxleaf() < 1) return (0);
       cpuid(&c, 1, 0); r = c.c;
       break;
       if (cpuid_maxleaf() < 1) return (0);
       cpuid(&c, 1, 0); r = c.c;
       break;
+    case CPUID_7_0_B:
+      if (cpuid_maxleaf() < 7) return (0);
+      cpuid(&c, 7, 0); r = c.b;
+      break;
     default:
       assert(!"unknown cpuid leaf");
   }
     default:
       assert(!"unknown cpuid leaf");
   }
@@ -139,6 +145,7 @@ static int rdrand_works_p(unsigned op)
 
   switch (op) {
     case OP_RDRAND: what = "RDRAND"; break;
 
   switch (op) {
     case OP_RDRAND: what = "RDRAND"; break;
+    case OP_RDSEED: what = "RDSEED"; break;
     default: assert(!"unexpected op");
   }
 
     default: assert(!"unexpected op");
   }
 
@@ -527,6 +534,9 @@ int cpu_feature_p(int feat)
     CASE_CPUFEAT(X86_PCLMUL, "x86:pclmul",
                 cpuid_feature_p(CPUID_1_C, CPUID1C_PCLMUL) &&
                 xmm_registers_available_p());
     CASE_CPUFEAT(X86_PCLMUL, "x86:pclmul",
                 cpuid_feature_p(CPUID_1_C, CPUID1C_PCLMUL) &&
                 xmm_registers_available_p());
+    CASE_CPUFEAT(X86_RDSEED, "x86:rdseed",
+                cpuid_feature_p(CPUID_7_0_B, CPUID70B_RDSEED) &&
+                rdrand_works_p(OP_RDSEED));
 #endif
 #ifdef CAPMAP
 #  define FEATP__CASE(feat, tok)                                       \
 #endif
 #ifdef CAPMAP
 #  define FEATP__CASE(feat, tok)                                       \
index 7c08382..2c78d92 100644 (file)
@@ -180,12 +180,13 @@ enum {
   CPUFEAT_ARM_NEON,                    /* Advanced SIMD (v1 or v2) */
   CPUFEAT_ARM_V4,                      /* VFPv4 and/or SIMD v2 */
   CPUFEAT_ARM_D32,                     /* 32 double registers, not 16 */
   CPUFEAT_ARM_NEON,                    /* Advanced SIMD (v1 or v2) */
   CPUFEAT_ARM_V4,                      /* VFPv4 and/or SIMD v2 */
   CPUFEAT_ARM_D32,                     /* 32 double registers, not 16 */
-  CPUFEAT_X86_RDRAND,                  /* Built-in entropy source */
+  CPUFEAT_X86_RDRAND,                  /* Built-in cooked entropy source */
   CPUFEAT_ARM_AES,                     /* AES instructions */
   CPUFEAT_X86_AVX,                     /* AVX 1 (i.e., 256-bit YMM regs) */
   CPUFEAT_X86_SSSE3,                   /* Supplementary SSE 3 */
   CPUFEAT_X86_PCLMUL,                  /* Carry-less multiplication */
   CPUFEAT_ARM_AES,                     /* AES instructions */
   CPUFEAT_X86_AVX,                     /* AVX 1 (i.e., 256-bit YMM regs) */
   CPUFEAT_X86_SSSE3,                   /* Supplementary SSE 3 */
   CPUFEAT_X86_PCLMUL,                  /* Carry-less multiplication */
-  CPUFEAT_ARM_PMULL                    /* Polynomial multiplication */
+  CPUFEAT_ARM_PMULL,                   /* Polynomial multiplication */
+  CPUFEAT_X86_RDSEED                   /* Built-in raw entropy source */
 };
 
 extern int cpu_feature_p(int /*feat*/);
 };
 
 extern int cpu_feature_p(int /*feat*/);
index 84ff893..c06cbdf 100644 (file)
@@ -653,6 +653,7 @@ libcatacomb.so.2 catacomb2 #MINVER#
        rand_seed@Base 2.2.3
        rand_quick@Base 2.5.2
        (optional|arch=i386 amd64)rand_quick_x86ish_rdrand@Base 2.5.0
        rand_seed@Base 2.2.3
        rand_quick@Base 2.5.2
        (optional|arch=i386 amd64)rand_quick_x86ish_rdrand@Base 2.5.0
+       (optional|arch=i386 amd64)rand_quick_x86ish_rdseed@Base 2.5.99~
        rand_key@Base 2.5.2
        rand_add@Base 2.2.3
        rand_goodbits@Base 2.2.3
        rand_key@Base 2.5.2
        rand_add@Base 2.2.3
        rand_goodbits@Base 2.2.3
index 70907fe..b91a937 100644 (file)
@@ -74,6 +74,34 @@ FUNC(rand_quick_x86ish_rdrand)
        // Failed.
        mov     eax, -1
        jmp     9f
        // Failed.
        mov     eax, -1
        jmp     9f
+ENDFUNC
+
+FUNC(rand_quick_x86ish_rdseed)
+       // Enter with a pointer to the random context in the first argument.
+       // Return zero on success, or -1 on error.
+
+#if CPUFAM_X86
+       mov     edx, [SP + 4]
+       stalloc 28
+#endif
+#if CPUFAM_AMD64 && ABI_SYSV
+       stalloc 8
+#endif
+#if CPUFAM_AMD64 && ABI_WIN
+       stalloc 40
+#endif
+  endprologue
+
+       // Try to fetch a random number.
+       mov     COUNT, 16
+0:     rdseed  AX
+       jc      1f
+       dec     COUNT
+       jnz     0b
+
+       // Failed.
+       mov     eax, -1
+       jmp     9f
 
        // Success.
 1:
 
        // Success.
 1:
index 304c68d..3b05633 100644 (file)
@@ -163,11 +163,14 @@ static int trivial_quick(rand_pool *r) { return (-1); }
 
 #if CPUFAM_X86 || CPUFAM_AMD64
 extern int rand_quick_x86ish_rdrand(rand_pool */*r*/);
 
 #if CPUFAM_X86 || CPUFAM_AMD64
 extern int rand_quick_x86ish_rdrand(rand_pool */*r*/);
+extern int rand_quick_x86ish_rdseed(rand_pool */*r*/);
 #endif
 
 static quick__functype *pick_quick(void)
 {
 #if CPUFAM_X86 || CPUFAM_AMD64
 #endif
 
 static quick__functype *pick_quick(void)
 {
 #if CPUFAM_X86 || CPUFAM_AMD64
+  DISPATCH_PICK_COND(rand_quick, rand_quick_x86ish_rdseed,
+                    cpu_feature_p(CPUFEAT_X86_RDSEED));
   DISPATCH_PICK_COND(rand_quick, rand_quick_x86ish_rdrand,
                     cpu_feature_p(CPUFEAT_X86_RDRAND));
 #endif
   DISPATCH_PICK_COND(rand_quick, rand_quick_x86ish_rdrand,
                     cpu_feature_p(CPUFEAT_X86_RDRAND));
 #endif