X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/catacomb/blobdiff_plain/11b179777b6b29afe0c960f62d7e2ea33b01cccd..fac645f7780c7673775f09fe625651f600f7ee7b:/base/dispatch.c diff --git a/base/dispatch.c b/base/dispatch.c index 4b5e17a9..eedf0172 100644 --- a/base/dispatch.c +++ b/base/dispatch.c @@ -30,6 +30,8 @@ #include "config.h" #include +#include +#include #include #include @@ -85,8 +87,11 @@ static void cpuid(struct cpuid *cc, unsigned a, unsigned c) #ifdef __GNUC__ /* Stupid dance to detect whether the CPUID instruction is available. */ f = getflags(); - if (!(setflags(f | EFLAGS_ID) & EFLAGS_ID)) return; - if ( setflags(f & ~EFLAGS_ID) & EFLAGS_ID ) return; + if (!(setflags(f | EFLAGS_ID) & EFLAGS_ID) || + setflags(f & ~EFLAGS_ID) & EFLAGS_ID) { + dispatch_debug("CPUID instruction not available"); + return; + } setflags(f); /* Alas, EBX is magical in PIC code, so abuse ESI instead. This isn't @@ -95,6 +100,8 @@ static void cpuid(struct cpuid *cc, unsigned a, unsigned c) __asm__ ("pushl %%ebx; cpuid; movl %%ebx, %%esi; popl %%ebx" : "=a" (cc->a), "=S" (cc->b), "=c" (cc->c), "=d" (cc->d) : "a" (a) , "c" (c)); +#else + dispatch_debug("GNU inline assembler not available; can't CPUID"); #endif } @@ -146,6 +153,7 @@ static int xmm_registers_available_p(void) : "%ecx", "%edx"); return (f); #else + dispatch_debug("GNU inline assembler not available; can't check for XMM"); return (0); #endif } @@ -154,6 +162,31 @@ static int xmm_registers_available_p(void) /*----- External interface ------------------------------------------------*/ +/* --- @dispatch_debug@ --- * + * + * Arguments: @const char *fmt@ = a format string + * @...@ = additional arguments + * + * Returns: --- + * + * Use: Writes a formatted message to standard output if dispatch + * debugging is enabled. + */ + +void dispatch_debug(const char *fmt, ...) +{ + va_list ap; + const char *e = getenv("CATACOMB_CPUDISPATCH_DEBUG"); + + if (e && *e != 'n' && *e != '0') { + va_start(ap, fmt); + fputs("Catacomb CPUDISPATCH: ", stderr); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); + } +} + /* --- @check_env@ --- * * * Arguments: @const char *ftok@ = feature token @@ -202,30 +235,41 @@ static int IGNORABLE check_env(const char *ftok) #include +static int IGNORABLE + feat_debug(const char *ftok, const char *check, int verdict) +{ + if (verdict >= 0) { + dispatch_debug("feature `%s': %s -> %s", ftok, check, + verdict ? "available" : "absent"); + } + return (verdict); +} + int cpu_feature_p(int feat) { int IGNORABLE f; IGNORE(f); -#define CHECK_ENV(ftok) \ - do { if ((f = check_env(ftok)) >= 0) return (f); } while (0) +#define CASE_CPUFEAT(feat, ftok, cond) case CPUFEAT_##feat: \ + if ((f = feat_debug(ftok, "environment override", \ + check_env(ftok))) >= 0) \ + return (f); \ + else \ + return (feat_debug(ftok, "runtime probe", cond)); switch (feat) { #ifdef CPUFAM_X86 - case CPUFEAT_X86_SSE2: { - CHECK_ENV("x86:sse2"); - return (xmm_registers_available_p() && - cpuid_features_p(CPUID1D_SSE2, 0)); - } - case CPUFEAT_X86_AESNI: { - check_env("x86:aesni"); - return (xmm_registers_available_p() && - cpuid_features_p(CPUID1D_SSE2, CPUID1C_AESNI)); - } + CASE_CPUFEAT(X86_SSE2, "x86:sse2", + xmm_registers_available_p() && + cpuid_features_p(CPUID1D_SSE2, 0)); + CASE_CPUFEAT(X86_AESNI, "x86:aesni", + xmm_registers_available_p() && + cpuid_features_p(CPUID1D_SSE2, CPUID1C_AESNI)); #endif default: + dispatch_debug("denying unknown feature %d", feat); return (0); } -#undef CHECK_ENV +#undef CASE_CPUFEAT } /*----- That's all, folks -------------------------------------------------*/