From: Mark Wooding Date: Sun, 5 Apr 2020 23:52:56 +0000 (+0000) Subject: base/dispatch.c: Make `cpuid_feature_p' more easily extensible. X-Git-Tag: 2.6.0~5 X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/commitdiff_plain/0ed9f882cdf9d0b4428459f7d5496610d53ca4c9 base/dispatch.c: Make `cpuid_feature_p' more easily extensible. It turns out that Intel scatter feature flags throughout the various CPUID leaves. Change the interface for checking these flags so that we can cover more ground without too much extra work. * Firstly, rename the function to `cpuid_feature_p' because it's only really useful for checking one feature at a time. * Secondly, make the first argument be a code indicating which particular `cpuid' output we're interested in; the second is still a mask used to check for the bit we're interested in. Obviously this involves changing all of the callers too. --- diff --git a/base/dispatch.c b/base/dispatch.c index 71a9da95..7652f323 100644 --- a/base/dispatch.c +++ b/base/dispatch.c @@ -29,6 +29,7 @@ #include "config.h" +#include #include #include #include @@ -43,14 +44,20 @@ #if CPUFAM_X86 || CPUFAM_AMD64 +enum { + CPUID_1_D, /* eax = 1 => edx&?? */ # define CPUID1D_SSE2 (1u << 26) # define CPUID1D_FXSR (1u << 24) + + CPUID_1_C, /* eax = 1 => ecx&?? */ # define CPUID1C_PCLMUL (1u << 1) # define CPUID1C_SSSE3 (1u << 9) # define CPUID1C_AESNI (1u << 25) # define CPUID1C_AVX (1u << 28) # define CPUID1C_RDRAND (1u << 30) +}; + 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); @@ -69,21 +76,33 @@ static void cpuid(struct cpuid *cc, unsigned a, unsigned c) static unsigned cpuid_maxleaf(void) { struct cpuid c; cpuid(&c, 0, 0); return (c.a); } -/* --- @cpuid_features_p@ --- * +/* --- @cpuid_feature_p@ --- * * - * Arguments: @unsigned dbits@ = bits to check in EDX - * @unsigned cbits@ = bits to check in ECX + * Arguments: @unsigned leaf@ = leaf to look up + * @unsigned bits@ = bits to check * - * Returns: Nonzero if all the requested bits are set in the CPUID result - * on leaf 1. + * Returns: Nonzero if all the requested bits are set in the requested + * CPUID result. */ -static int cpuid_features_p(unsigned dbits, unsigned cbits) +static int cpuid_feature_p(unsigned leaf, unsigned bits) { struct cpuid c; - if (cpuid_maxleaf() < 1) return (0); - cpuid(&c, 1, 0); - return ((c.d & dbits) == dbits && (c.c & cbits) == cbits); + unsigned r; + + switch (leaf) { + case CPUID_1_D: + if (cpuid_maxleaf() < 1) return (0); + cpuid(&c, 1, 0); r = c.d; + break; + case CPUID_1_C: + if (cpuid_maxleaf() < 1) return (0); + cpuid(&c, 1, 0); r = c.c; + break; + default: + assert(!"unknown cpuid leaf"); + } + return ((r&bits) == bits); } /* --- @xmm_registers_available_p@ --- * @@ -483,21 +502,22 @@ int cpu_feature_p(int feat) switch (feat) { #if CPUFAM_X86 || CPUFAM_AMD64 CASE_CPUFEAT(X86_SSE2, "x86:sse2", - cpuid_features_p(CPUID1D_SSE2, 0) && + cpuid_feature_p(CPUID_1_D, CPUID1D_SSE2) && xmm_registers_available_p()); CASE_CPUFEAT(X86_AESNI, "x86:aesni", - cpuid_features_p(CPUID1D_SSE2, CPUID1C_AESNI) && + cpuid_feature_p(CPUID_1_D, CPUID1C_AESNI) && xmm_registers_available_p()); CASE_CPUFEAT(X86_RDRAND, "x86:rdrand", - cpuid_features_p(0, CPUID1C_RDRAND) && rdrand_works_p()); + cpuid_feature_p(CPUID_1_C, CPUID1C_RDRAND) && + rdrand_works_p()); CASE_CPUFEAT(X86_AVX, "x86:avx", - cpuid_features_p(0, CPUID1C_AVX) && + cpuid_feature_p(CPUID_1_C, CPUID1C_AVX) && xmm_registers_available_p()); CASE_CPUFEAT(X86_SSSE3, "x86:ssse3", - cpuid_features_p(0, CPUID1C_SSSE3) && + cpuid_feature_p(CPUID_1_C, CPUID1C_SSSE3) && xmm_registers_available_p()); CASE_CPUFEAT(X86_PCLMUL, "x86:pclmul", - cpuid_features_p(0, CPUID1C_PCLMUL) && + cpuid_feature_p(CPUID_1_C, CPUID1C_PCLMUL) && xmm_registers_available_p()); #endif #ifdef CAPMAP