/// Checking `rdrand'.
FUNC(dispatch_x86ish_rdrand)
- // Enter with one argument: a pointer X_OUT to a 32-bit word. Try to
- // generate a random word using `rdrand'. If successful, set *X_OUT
- // to the generated word, and return zero; otherwise, return -1.
+ // 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.
#if CPUFAM_X86
+# define OP eax
# define X_OUT edx
# define COUNT ecx
- mov X_OUT, [SP + 4]
+ mov OP, [SP + 4]
+ mov X_OUT, [SP + 8]
#endif
#if CPUFAM_AMD64 && ABI_SYSV
-# define X_OUT rdi
+# define OP edi
+# define X_OUT rsi
# define COUNT ecx
#endif
#if CPUFAM_AMD64 && ABI_WIN
-# define X_OUT rcx
-# define COUNT edx
+# define OP rcx
+# define X_OUT rdx
+# define COUNT r8d
#endif
endprologue
jc 9f
dec COUNT
jnz 0b
+ jmp 8f
// Failed to come up with a random value.
- mov eax, -1
+8: mov eax, -1
ret
// Success.
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)
{
* 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);
}
xmm_registers_available_p());
CASE_CPUFEAT(X86_RDRAND, "x86:rdrand",
cpuid_feature_p(CPUID_1_C, CPUID1C_RDRAND) &&
- rdrand_works_p());
+ rdrand_works_p(OP_RDRAND));
CASE_CPUFEAT(X86_AVX, "x86:avx",
cpuid_feature_p(CPUID_1_C, CPUID1C_AVX) &&
xmm_registers_available_p());