From 1b07c4f340465551b7d12c3be3bcecd258a3c32d Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Mon, 6 Apr 2020 00:02:41 +0000 Subject: [PATCH] base/dispatch.c, base/dispatch-x86ish.S: Add opcode to `rdrand_works_p'. I want to add support foer the `rdseed' instruction, but this might be broken on AMD64 like `rdrand'. Rather than duplicate this logic, add an opcode argument to the checking functions. --- base/dispatch-x86ish.S | 22 ++++++++++++++-------- base/dispatch.c | 24 ++++++++++++++++-------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/base/dispatch-x86ish.S b/base/dispatch-x86ish.S index 94f44ee1..b3b6d1cb 100644 --- a/base/dispatch-x86ish.S +++ b/base/dispatch-x86ish.S @@ -158,22 +158,27 @@ ENDFUNC /// 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 @@ -182,9 +187,10 @@ FUNC(dispatch_x86ish_rdrand) 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. diff --git a/base/dispatch.c b/base/dispatch.c index 7652f323..bda7f88e 100644 --- a/base/dispatch.c +++ b/base/dispatch.c @@ -61,7 +61,7 @@ enum { 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) { @@ -130,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); } @@ -509,7 +517,7 @@ int cpu_feature_p(int feat) 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()); -- 2.11.0