123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- #ifndef CPUSUPPORT_H_
- #define CPUSUPPORT_H_
- /*
- * To enable support for non-portable CPU features at compile time, one or
- * more CPUSUPPORT_ARCH_FEATURE macros should be defined. This can be done
- * directly on the compiler command line via -D CPUSUPPORT_ARCH_FEATURE or
- * -D CPUSUPPORT_ARCH_FEATURE=1; or a file can be created with the
- * necessary #define lines and then -D CPUSUPPORT_CONFIG_FILE=cpuconfig.h
- * (or similar) can be provided to include that file here.
- */
- #ifdef CPUSUPPORT_CONFIG_FILE
- #include CPUSUPPORT_CONFIG_FILE
- #endif
- /**
- * The CPUSUPPORT_FEATURE macro declares the necessary variables and
- * functions for detecting CPU feature support at run time. The function
- * defined in the macro acts to cache the result of the ..._detect function
- * using the ..._present and ..._init variables. The _detect function and the
- * _present and _init variables are turn defined by CPUSUPPORT_FEATURE_DECL in
- * appropriate cpusupport_foo_bar.c file.
- *
- * In order to allow CPUSUPPORT_FEATURE to be used for features which do not
- * have corresponding CPUSUPPORT_FEATURE_DECL blocks in another source file,
- * we abuse the C preprocessor: If CPUSUPPORT_${enabler} is defined to 1, then
- * we access _present_1, _init_1, and _detect_1; but if it is not defined, we
- * access _present_CPUSUPPORT_${enabler} etc., which we define as static, thus
- * preventing the compiler from emitting a reference to an external symbol.
- *
- * In this way, it becomes possible to issue CPUSUPPORT_FEATURE invocations
- * for nonexistent features without running afoul of the requirement that
- * "If an identifier declared with external linkage is used... in the entire
- * program there shall be exactly one external definition" (C99 standard, 6.9
- * paragraph 5). In practice, this means that users of the cpusupport code
- * can omit build and runtime detection files without changing the framework
- * code.
- */
- #define CPUSUPPORT_FEATURE__(arch_feature, enabler, enabled) \
- static int cpusupport_ ## arch_feature ## _present ## _CPUSUPPORT_ ## enabler; \
- static int cpusupport_ ## arch_feature ## _init ## _CPUSUPPORT_ ## enabler; \
- static inline int cpusupport_ ## arch_feature ## _detect ## _CPUSUPPORT_ ## enabler(void) { return (0); } \
- extern int cpusupport_ ## arch_feature ## _present_ ## enabled; \
- extern int cpusupport_ ## arch_feature ## _init_ ## enabled; \
- int cpusupport_ ## arch_feature ## _detect_ ## enabled(void); \
- \
- static inline int \
- cpusupport_ ## arch_feature(void) \
- { \
- \
- if (cpusupport_ ## arch_feature ## _present_ ## enabled) \
- return (1); \
- else if (cpusupport_ ## arch_feature ## _init_ ## enabled) \
- return (0); \
- cpusupport_ ## arch_feature ## _present_ ## enabled = \
- cpusupport_ ## arch_feature ## _detect_ ## enabled(); \
- cpusupport_ ## arch_feature ## _init_ ## enabled = 1; \
- return (cpusupport_ ## arch_feature ## _present_ ## enabled); \
- } \
- static void (* cpusupport_ ## arch_feature ## _dummyptr)(void); \
- static inline void \
- cpusupport_ ## arch_feature ## _dummyfunc(void) \
- { \
- \
- (void)cpusupport_ ## arch_feature ## _present ## _CPUSUPPORT_ ## enabler; \
- (void)cpusupport_ ## arch_feature ## _init ## _CPUSUPPORT_ ## enabler; \
- (void)cpusupport_ ## arch_feature ## _detect ## _CPUSUPPORT_ ## enabler; \
- (void)cpusupport_ ## arch_feature ## _present_ ## enabled; \
- (void)cpusupport_ ## arch_feature ## _init_ ## enabled; \
- (void)cpusupport_ ## arch_feature ## _detect_ ## enabled; \
- (void)cpusupport_ ## arch_feature ## _dummyptr; \
- } \
- static void (* cpusupport_ ## arch_feature ## _dummyptr)(void) = cpusupport_ ## arch_feature ## _dummyfunc; \
- struct cpusupport_ ## arch_feature ## _dummy
- #define CPUSUPPORT_FEATURE_(arch_feature, enabler, enabled) \
- CPUSUPPORT_FEATURE__(arch_feature, enabler, enabled)
- #define CPUSUPPORT_FEATURE(arch, feature, enabler) \
- CPUSUPPORT_FEATURE_(arch ## _ ## feature, enabler, CPUSUPPORT_ ## enabler)
- /**
- * CPUSUPPORT_FEATURE_DECL(arch, feature):
- * Macro which defines variables and provides a function declaration for
- * detecting the presence of "feature" on the "arch" architecture. The
- * function body following this macro expansion must return nonzero if the
- * feature is present, or zero if the feature is not present or the detection
- * fails for any reason.
- */
- #define CPUSUPPORT_FEATURE_DECL(arch, feature) \
- extern int cpusupport_ ## arch ## _ ## feature ## _present_1; \
- extern int cpusupport_ ## arch ## _ ## feature ## _init_1; \
- int cpusupport_ ## arch ## _ ## feature ## _present_1 = 0; \
- int cpusupport_ ## arch ## _ ## feature ## _init_1 = 0; \
- int cpusupport_ ## arch ## _ ## feature ## _detect_1(void); \
- int \
- cpusupport_ ## arch ## _ ## feature ## _detect_1(void)
- /**
- * CPUSUPPORT_VALIDATE(hwvar, success_value, cpusupport_checks, check):
- * Check if we can enable ${success_value}, given the ${cpusupport_checks} and
- * ${check}; if so, write to ${hwvar}. If the ${cpusupport_checks} pass but
- * the ${check} is non-zero, produce a warning which includes a stringified
- * ${success_value}, then fallthrough.
- */
- #define CPUSUPPORT_VALIDATE(hwvar, success_value, cpusupport_checks, \
- check) do { \
- if ((cpusupport_checks)) { \
- if ((check) == 0) { \
- (hwvar) = (success_value); \
- return; \
- } else { \
- warn0("Disabling " #success_value \
- " due to failed self-test"); \
- } \
- } \
- } while (0)
- /**
- * List of features. If a feature here is not enabled by the appropriate
- * CPUSUPPORT_ARCH_FEATURE macro being defined, it has no effect; but if the
- * relevant macro may be defined (e.g., by Build/cpusupport.sh successfully
- * compiling Build/cpusupport-ARCH-FEATURE.c) then the C file containing the
- * corresponding run-time detection code (cpusupport_arch_feature.c) must be
- * compiled and linked in.
- *
- * There are a few features for which we do not have run-time checks:
- * - X86_CPUID: compile-time is enough; if __get_cpuid() fails, then all the
- * x86 detection features will fail, but there's nothing we can
- * do about that.
- * - X86_CPUID_COUNT: ditto.
- * - X86_SSE42_64: the cpuid check tells us if the CPU supports SSE4.2, but
- * that says nothing about whether it's in 64-bit mode.
- */
- CPUSUPPORT_FEATURE(x86, aesni, X86_AESNI);
- CPUSUPPORT_FEATURE(x86, rdrand, X86_RDRAND);
- CPUSUPPORT_FEATURE(x86, shani, X86_SHANI);
- CPUSUPPORT_FEATURE(x86, sse2, X86_SSE2);
- CPUSUPPORT_FEATURE(x86, sse42, X86_SSE42);
- CPUSUPPORT_FEATURE(x86, ssse3, X86_SSSE3);
- CPUSUPPORT_FEATURE(arm, aes, ARM_AES);
- CPUSUPPORT_FEATURE(arm, crc32_64, ARM_CRC32_64);
- CPUSUPPORT_FEATURE(arm, sha256, ARM_SHA256);
- #endif /* !CPUSUPPORT_H_ */
|