X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/blobdiff_plain/7875ad25119a0099dfcfba3fbd256e404c722ff3..cd303963aec7291de8aabf9aa04d1423fe7dcac4:/base/dispatch.c diff --git a/base/dispatch.c b/base/dispatch.c index c8bbc0b9..7806d405 100644 --- a/base/dispatch.c +++ b/base/dispatch.c @@ -54,6 +54,7 @@ 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 *); static void cpuid(struct cpuid *cc, unsigned a, unsigned c) { @@ -101,6 +102,40 @@ static int xmm_registers_available_p(void) return (f); } +/* --- @rdrand_works_p@ --- * + * + * + * Arguments: --- + * + * Returns: Nonzero if the `rdrand' instruction actually works. Assumes + * that it's already been verified to be safe to issue. + */ + +static int rdrand_works_p(void) +{ + unsigned ref, x, i; + + /* 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; + for (i = 0; i < 4; i++) { + if (dispatch_x86ish_rdrand(&x)) goto fail; + if (x != ref) goto not_stuck; + } + dispatch_debug("RDRAND always returns 0x%08x!", ref); + return (0); + +not_stuck: + dispatch_debug("RDRAND instruction looks plausible"); + return (1); + +fail: + dispatch_debug("RDRAND instruction fails too often"); + return (0); +} + #endif /*----- General feature probing using auxiliary vectors -------------------*/ @@ -191,6 +226,7 @@ static unsigned hwcaps = 0; # define WANTAUX(_) \ WANT_AT_HWCAP(_) # define CAPMAP(_) \ + _(ARM_NEON, "arm:neon") \ _(ARM_AES, "arm:aes") \ _(ARM_PMULL, "arm:pmull") #endif @@ -311,6 +347,7 @@ static void probe_hwcaps(void) # endif #endif #if CPUFAM_ARM64 + if (probed.hwcap & HWCAP_ASIMD) hw |= HF_ARM_NEON; if (probed.hwcap & HWCAP_AES) hw |= HF_ARM_AES; if (probed.hwcap & HWCAP_PMULL) hw |= HF_ARM_PMULL; #endif @@ -397,14 +434,14 @@ static int IGNORABLE check_env(const char *ftok) if (!p) return (-1); for (;;) { - while (isspace((unsigned char)*p)) p++; + while (ISSPACE(*p)) p++; if (!*p) return (-1); switch (*p) { case '+': d = +1; p++; break; case '-': d = 0; p++; break; default: d = -1; break; } - for (q = p; *q && !isspace((unsigned char)*q); q++); + for (q = p; *q && !ISSPACE(*q); q++); if (d >= 0) { for (pp = ftok; p < q && *pp && *p == *pp; p++, pp++); if ((p == q && !*pp) || (*p == '*' && p + 1 == q)) return (d); @@ -453,7 +490,7 @@ int cpu_feature_p(int feat) cpuid_features_p(CPUID1D_SSE2, CPUID1C_AESNI) && xmm_registers_available_p()); CASE_CPUFEAT(X86_RDRAND, "x86:rdrand", - cpuid_features_p(0, CPUID1C_RDRAND)); + cpuid_features_p(0, CPUID1C_RDRAND) && rdrand_works_p()); CASE_CPUFEAT(X86_AVX, "x86:avx", cpuid_features_p(0, CPUID1C_AVX) && xmm_registers_available_p());