cpusupport.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #ifndef CPUSUPPORT_H_
  2. #define CPUSUPPORT_H_
  3. /*
  4. * To enable support for non-portable CPU features at compile time, one or
  5. * more CPUSUPPORT_ARCH_FEATURE macros should be defined. This can be done
  6. * directly on the compiler command line via -D CPUSUPPORT_ARCH_FEATURE or
  7. * -D CPUSUPPORT_ARCH_FEATURE=1; or a file can be created with the
  8. * necessary #define lines and then -D CPUSUPPORT_CONFIG_FILE=cpuconfig.h
  9. * (or similar) can be provided to include that file here.
  10. */
  11. #ifdef CPUSUPPORT_CONFIG_FILE
  12. #include CPUSUPPORT_CONFIG_FILE
  13. #endif
  14. /**
  15. * The CPUSUPPORT_FEATURE macro declares the necessary variables and
  16. * functions for detecting CPU feature support at run time. The function
  17. * defined in the macro acts to cache the result of the ..._detect function
  18. * using the ..._present and ..._init variables. The _detect function and the
  19. * _present and _init variables are turn defined by CPUSUPPORT_FEATURE_DECL in
  20. * appropriate cpusupport_foo_bar.c file.
  21. *
  22. * In order to allow CPUSUPPORT_FEATURE to be used for features which do not
  23. * have corresponding CPUSUPPORT_FEATURE_DECL blocks in another source file,
  24. * we abuse the C preprocessor: If CPUSUPPORT_${enabler} is defined to 1, then
  25. * we access _present_1, _init_1, and _detect_1; but if it is not defined, we
  26. * access _present_CPUSUPPORT_${enabler} etc., which we define as static, thus
  27. * preventing the compiler from emitting a reference to an external symbol.
  28. *
  29. * In this way, it becomes possible to issue CPUSUPPORT_FEATURE invocations
  30. * for nonexistent features without running afoul of the requirement that
  31. * "If an identifier declared with external linkage is used... in the entire
  32. * program there shall be exactly one external definition" (C99 standard, 6.9
  33. * paragraph 5). In practice, this means that users of the cpusupport code
  34. * can omit build and runtime detection files without changing the framework
  35. * code.
  36. */
  37. #define CPUSUPPORT_FEATURE__(arch_feature, enabler, enabled) \
  38. static int cpusupport_ ## arch_feature ## _present ## _CPUSUPPORT_ ## enabler; \
  39. static int cpusupport_ ## arch_feature ## _init ## _CPUSUPPORT_ ## enabler; \
  40. static inline int cpusupport_ ## arch_feature ## _detect ## _CPUSUPPORT_ ## enabler(void) { return (0); } \
  41. extern int cpusupport_ ## arch_feature ## _present_ ## enabled; \
  42. extern int cpusupport_ ## arch_feature ## _init_ ## enabled; \
  43. int cpusupport_ ## arch_feature ## _detect_ ## enabled(void); \
  44. \
  45. static inline int \
  46. cpusupport_ ## arch_feature(void) \
  47. { \
  48. \
  49. if (cpusupport_ ## arch_feature ## _present_ ## enabled) \
  50. return (1); \
  51. else if (cpusupport_ ## arch_feature ## _init_ ## enabled) \
  52. return (0); \
  53. cpusupport_ ## arch_feature ## _present_ ## enabled = \
  54. cpusupport_ ## arch_feature ## _detect_ ## enabled(); \
  55. cpusupport_ ## arch_feature ## _init_ ## enabled = 1; \
  56. return (cpusupport_ ## arch_feature ## _present_ ## enabled); \
  57. } \
  58. static void (* cpusupport_ ## arch_feature ## _dummyptr)(void); \
  59. static inline void \
  60. cpusupport_ ## arch_feature ## _dummyfunc(void) \
  61. { \
  62. \
  63. (void)cpusupport_ ## arch_feature ## _present ## _CPUSUPPORT_ ## enabler; \
  64. (void)cpusupport_ ## arch_feature ## _init ## _CPUSUPPORT_ ## enabler; \
  65. (void)cpusupport_ ## arch_feature ## _detect ## _CPUSUPPORT_ ## enabler; \
  66. (void)cpusupport_ ## arch_feature ## _present_ ## enabled; \
  67. (void)cpusupport_ ## arch_feature ## _init_ ## enabled; \
  68. (void)cpusupport_ ## arch_feature ## _detect_ ## enabled; \
  69. (void)cpusupport_ ## arch_feature ## _dummyptr; \
  70. } \
  71. static void (* cpusupport_ ## arch_feature ## _dummyptr)(void) = cpusupport_ ## arch_feature ## _dummyfunc; \
  72. struct cpusupport_ ## arch_feature ## _dummy
  73. #define CPUSUPPORT_FEATURE_(arch_feature, enabler, enabled) \
  74. CPUSUPPORT_FEATURE__(arch_feature, enabler, enabled)
  75. #define CPUSUPPORT_FEATURE(arch, feature, enabler) \
  76. CPUSUPPORT_FEATURE_(arch ## _ ## feature, enabler, CPUSUPPORT_ ## enabler)
  77. /**
  78. * CPUSUPPORT_FEATURE_DECL(arch, feature):
  79. * Macro which defines variables and provides a function declaration for
  80. * detecting the presence of "feature" on the "arch" architecture. The
  81. * function body following this macro expansion must return nonzero if the
  82. * feature is present, or zero if the feature is not present or the detection
  83. * fails for any reason.
  84. */
  85. #define CPUSUPPORT_FEATURE_DECL(arch, feature) \
  86. extern int cpusupport_ ## arch ## _ ## feature ## _present_1; \
  87. extern int cpusupport_ ## arch ## _ ## feature ## _init_1; \
  88. int cpusupport_ ## arch ## _ ## feature ## _present_1 = 0; \
  89. int cpusupport_ ## arch ## _ ## feature ## _init_1 = 0; \
  90. int cpusupport_ ## arch ## _ ## feature ## _detect_1(void); \
  91. int \
  92. cpusupport_ ## arch ## _ ## feature ## _detect_1(void)
  93. /**
  94. * CPUSUPPORT_VALIDATE(hwvar, success_value, cpusupport_checks, check):
  95. * Check if we can enable ${success_value}, given the ${cpusupport_checks} and
  96. * ${check}; if so, write to ${hwvar}. If the ${cpusupport_checks} pass but
  97. * the ${check} is non-zero, produce a warning which includes a stringified
  98. * ${success_value}, then fallthrough.
  99. */
  100. #define CPUSUPPORT_VALIDATE(hwvar, success_value, cpusupport_checks, \
  101. check) do { \
  102. if ((cpusupport_checks)) { \
  103. if ((check) == 0) { \
  104. (hwvar) = (success_value); \
  105. return; \
  106. } else { \
  107. warn0("Disabling " #success_value \
  108. " due to failed self-test"); \
  109. } \
  110. } \
  111. } while (0)
  112. /**
  113. * List of features. If a feature here is not enabled by the appropriate
  114. * CPUSUPPORT_ARCH_FEATURE macro being defined, it has no effect; but if the
  115. * relevant macro may be defined (e.g., by Build/cpusupport.sh successfully
  116. * compiling Build/cpusupport-ARCH-FEATURE.c) then the C file containing the
  117. * corresponding run-time detection code (cpusupport_arch_feature.c) must be
  118. * compiled and linked in.
  119. *
  120. * There are a few features for which we do not have run-time checks:
  121. * - X86_CPUID: compile-time is enough; if __get_cpuid() fails, then all the
  122. * x86 detection features will fail, but there's nothing we can
  123. * do about that.
  124. * - X86_CPUID_COUNT: ditto.
  125. * - X86_SSE42_64: the cpuid check tells us if the CPU supports SSE4.2, but
  126. * that says nothing about whether it's in 64-bit mode.
  127. */
  128. CPUSUPPORT_FEATURE(x86, aesni, X86_AESNI);
  129. CPUSUPPORT_FEATURE(x86, rdrand, X86_RDRAND);
  130. CPUSUPPORT_FEATURE(x86, shani, X86_SHANI);
  131. CPUSUPPORT_FEATURE(x86, sse2, X86_SSE2);
  132. CPUSUPPORT_FEATURE(x86, sse42, X86_SSE42);
  133. CPUSUPPORT_FEATURE(x86, ssse3, X86_SSSE3);
  134. CPUSUPPORT_FEATURE(arm, aes, ARM_AES);
  135. CPUSUPPORT_FEATURE(arm, crc32_64, ARM_CRC32_64);
  136. CPUSUPPORT_FEATURE(arm, sha256, ARM_SHA256);
  137. #endif /* !CPUSUPPORT_H_ */