# define CPUID1C_PCLMUL (1u << 1)
# define CPUID1C_SSSE3 (1u << 9)
# define CPUID1C_AESNI (1u << 25)
+# define CPUID1C_OSXSAVE (1u << 27)
# define CPUID1C_AVX (1u << 28)
# define CPUID1C_RDRAND (1u << 30)
+ CPUID_7_0_B, /* eax = 7, ecx = 0 => ebx&?? */
+# define CPUID70B_AVX2 (1u << 5)
+# define CPUID70B_RDSEED (1u << 18)
};
struct cpuid { unsigned a, b, c, d; };
+struct xcr { unsigned lo, hi; };
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_xgetbv(struct xcr *z_out, unsigned c);
+extern int dispatch_x86ish_rdrand(unsigned op, unsigned *);
static void cpuid(struct cpuid *cc, unsigned a, unsigned c)
{
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");
}
return ((r&bits) == bits);
}
-/* --- @xmm_registers_available_p@ --- *
+/* --- @{x,y}mm_registers_available_p@ --- *
*
* Arguments: ---
*
- * Returns: Nonzero if the operating system has made the XMM registers
- * available for use.
+ * Returns: Nonzero if the operating system has made the XMM or YMM
+ * registers available for use.
*/
static int xmm_registers_available_p(void)
return (f);
}
+static int ymm_registers_available_p(void)
+{
+ struct xcr xcr0;
+ int f;
+
+ f = cpuid_feature_p(CPUID_1_C, CPUID1C_OSXSAVE);
+ dispatch_debug("XGETBV %savailable", f ? "" : "not ");
+ if (!f) return (0);
+
+ dispatch_x86ish_xgetbv(&xcr0, 0); f = (xcr0.lo&0x06) == 0x06;
+ dispatch_debug("YMM state %senabled", f ? "" : "not ");
+ if (!f) return (0);
+
+ return (1);
+}
+
/* --- @rdrand_works_p@ --- *
*
*
* 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;
+ case OP_RDSEED: what = "RDSEED"; 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);
}
unsigned hw;
DISPATCH_LOAD(hwcaps, hw);
- if (!(hwcaps & HF_PROBED)) { probe_hwcaps(); DISPATCH_LOAD(hwcaps, hw); }
+ if (!(hw & HF_PROBED)) { probe_hwcaps(); DISPATCH_LOAD(hwcaps, hw); }
return (hw);
}
cpuid_feature_p(CPUID_1_D, CPUID1D_SSE2) &&
xmm_registers_available_p());
CASE_CPUFEAT(X86_AESNI, "x86:aesni",
- cpuid_feature_p(CPUID_1_D, CPUID1C_AESNI) &&
+ cpuid_feature_p(CPUID_1_C, CPUID1C_AESNI) &&
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());
+ ymm_registers_available_p());
+ CASE_CPUFEAT(X86_AVX2, "x86:avx2",
+ cpuid_feature_p(CPUID_1_C, CPUID1C_AVX) &&
+ cpuid_feature_p(CPUID_7_0_B, CPUID70B_AVX2) &&
+ ymm_registers_available_p());
CASE_CPUFEAT(X86_SSSE3, "x86:ssse3",
cpuid_feature_p(CPUID_1_C, CPUID1C_SSSE3) &&
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) \