randen_detect.cc 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // Copyright 2017 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // HERMETIC NOTE: The randen_hwaes target must not introduce duplicate
  15. // symbols from arbitrary system and other headers, since it may be built
  16. // with different flags from other targets, using different levels of
  17. // optimization, potentially introducing ODR violations.
  18. #include "absl/random/internal/randen_detect.h"
  19. #if defined(__APPLE__) && defined(__aarch64__)
  20. #if defined(__has_include)
  21. #if __has_include(<arm/cpu_capabilities_public.h>)
  22. #include <arm/cpu_capabilities_public.h>
  23. #endif
  24. #endif
  25. #include <sys/sysctl.h>
  26. #include <sys/types.h>
  27. #endif
  28. #include <cstdint>
  29. #include <cstring>
  30. #include "absl/random/internal/platform.h"
  31. #include "absl/types/optional.h" // IWYU pragma: keep
  32. #if !defined(__UCLIBC__) && defined(__GLIBC__) && \
  33. (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 16))
  34. #define ABSL_HAVE_GETAUXVAL
  35. #endif
  36. #if defined(ABSL_ARCH_X86_64)
  37. #define ABSL_INTERNAL_USE_X86_CPUID
  38. #elif defined(ABSL_ARCH_PPC) || defined(ABSL_ARCH_ARM) || \
  39. defined(ABSL_ARCH_AARCH64)
  40. #if defined(__ANDROID__)
  41. #define ABSL_INTERNAL_USE_ANDROID_GETAUXVAL
  42. #define ABSL_INTERNAL_USE_GETAUXVAL
  43. #elif defined(__linux__) && defined(ABSL_HAVE_GETAUXVAL)
  44. #define ABSL_INTERNAL_USE_LINUX_GETAUXVAL
  45. #define ABSL_INTERNAL_USE_GETAUXVAL
  46. #endif
  47. #endif
  48. #if defined(ABSL_INTERNAL_USE_X86_CPUID)
  49. #if defined(_WIN32) || defined(_WIN64)
  50. #include <intrin.h> // NOLINT(build/include_order)
  51. #elif ABSL_HAVE_BUILTIN(__cpuid)
  52. // MSVC-equivalent __cpuid intrinsic declaration for clang-like compilers
  53. // for non-Windows build environments.
  54. extern void __cpuid(int[4], int);
  55. #else
  56. // MSVC-equivalent __cpuid intrinsic function.
  57. static void __cpuid(int cpu_info[4], int info_type) {
  58. __asm__ volatile("cpuid \n\t"
  59. : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]),
  60. "=d"(cpu_info[3])
  61. : "a"(info_type), "c"(0));
  62. }
  63. #endif
  64. #endif // ABSL_INTERNAL_USE_X86_CPUID
  65. // On linux, just use the c-library getauxval call.
  66. #if defined(ABSL_INTERNAL_USE_LINUX_GETAUXVAL)
  67. extern "C" unsigned long getauxval(unsigned long type); // NOLINT(runtime/int)
  68. static uint32_t GetAuxval(uint32_t hwcap_type) {
  69. return static_cast<uint32_t>(getauxval(hwcap_type));
  70. }
  71. #endif
  72. // On android, probe the system's C library for getauxval().
  73. // This is the same technique used by the android NDK cpu features library
  74. // as well as the google open-source cpu_features library.
  75. //
  76. // TODO(absl-team): Consider implementing a fallback of directly reading
  77. // /proc/self/auxval.
  78. #if defined(ABSL_INTERNAL_USE_ANDROID_GETAUXVAL)
  79. #include <dlfcn.h>
  80. static uint32_t GetAuxval(uint32_t hwcap_type) {
  81. // NOLINTNEXTLINE(runtime/int)
  82. typedef unsigned long (*getauxval_func_t)(unsigned long);
  83. dlerror(); // Cleaning error state before calling dlopen.
  84. void* libc_handle = dlopen("libc.so", RTLD_NOW);
  85. if (!libc_handle) {
  86. return 0;
  87. }
  88. uint32_t result = 0;
  89. void* sym = dlsym(libc_handle, "getauxval");
  90. if (sym) {
  91. getauxval_func_t func;
  92. memcpy(&func, &sym, sizeof(func));
  93. result = static_cast<uint32_t>((*func)(hwcap_type));
  94. }
  95. dlclose(libc_handle);
  96. return result;
  97. }
  98. #endif
  99. #if defined(__APPLE__) && defined(ABSL_ARCH_AARCH64)
  100. template <typename T>
  101. static absl::optional<T> ReadSysctlByName(const char* name) {
  102. T val;
  103. size_t val_size = sizeof(T);
  104. int ret = sysctlbyname(name, &val, &val_size, nullptr, 0);
  105. if (ret == -1) {
  106. return absl::nullopt;
  107. }
  108. return val;
  109. }
  110. #endif
  111. namespace absl {
  112. ABSL_NAMESPACE_BEGIN
  113. namespace random_internal {
  114. // The default return at the end of the function might be unreachable depending
  115. // on the configuration. Ignore that warning.
  116. #if defined(__clang__)
  117. #pragma clang diagnostic push
  118. #pragma clang diagnostic ignored "-Wunreachable-code-return"
  119. #endif
  120. // CPUSupportsRandenHwAes returns whether the CPU is a microarchitecture
  121. // which supports the crpyto/aes instructions or extensions necessary to use the
  122. // accelerated RandenHwAes implementation.
  123. //
  124. // 1. For x86 it is sufficient to use the CPUID instruction to detect whether
  125. // the cpu supports AES instructions. Done.
  126. //
  127. // Fon non-x86 it is much more complicated.
  128. //
  129. // 2. When ABSL_INTERNAL_USE_GETAUXVAL is defined, use getauxval() (either
  130. // the direct c-library version, or the android probing version which loads
  131. // libc), and read the hardware capability bits.
  132. // This is based on the technique used by boringssl uses to detect
  133. // cpu capabilities, and should allow us to enable crypto in the android
  134. // builds where it is supported.
  135. //
  136. // 3. When __APPLE__ is defined on AARCH64, use sysctlbyname().
  137. //
  138. // 4. Use the default for the compiler architecture.
  139. //
  140. bool CPUSupportsRandenHwAes() {
  141. #if defined(ABSL_INTERNAL_USE_X86_CPUID)
  142. // 1. For x86: Use CPUID to detect the required AES instruction set.
  143. int regs[4];
  144. __cpuid(reinterpret_cast<int*>(regs), 1);
  145. return regs[2] & (1 << 25); // AES
  146. #elif defined(ABSL_INTERNAL_USE_GETAUXVAL)
  147. // 2. Use getauxval() to read the hardware bits and determine
  148. // cpu capabilities.
  149. #define AT_HWCAP 16
  150. #define AT_HWCAP2 26
  151. #if defined(ABSL_ARCH_PPC)
  152. // For Power / PPC: Expect that the cpu supports VCRYPTO
  153. // See https://members.openpowerfoundation.org/document/dl/576
  154. // VCRYPTO should be present in POWER8 >= 2.07.
  155. // Uses Linux kernel constants from arch/powerpc/include/uapi/asm/cputable.h
  156. static const uint32_t kVCRYPTO = 0x02000000;
  157. const uint32_t hwcap = GetAuxval(AT_HWCAP2);
  158. return (hwcap & kVCRYPTO) != 0;
  159. #elif defined(ABSL_ARCH_ARM)
  160. // For ARM: Require crypto+neon
  161. // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500f/CIHBIBBA.html
  162. // Uses Linux kernel constants from arch/arm64/include/asm/hwcap.h
  163. static const uint32_t kNEON = 1 << 12;
  164. uint32_t hwcap = GetAuxval(AT_HWCAP);
  165. if ((hwcap & kNEON) == 0) {
  166. return false;
  167. }
  168. // And use it again to detect AES.
  169. static const uint32_t kAES = 1 << 0;
  170. const uint32_t hwcap2 = GetAuxval(AT_HWCAP2);
  171. return (hwcap2 & kAES) != 0;
  172. #elif defined(ABSL_ARCH_AARCH64)
  173. // For AARCH64: Require crypto+neon
  174. // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500f/CIHBIBBA.html
  175. static const uint32_t kNEON = 1 << 1;
  176. static const uint32_t kAES = 1 << 3;
  177. const uint32_t hwcap = GetAuxval(AT_HWCAP);
  178. return ((hwcap & kNEON) != 0) && ((hwcap & kAES) != 0);
  179. #endif
  180. #elif defined(__APPLE__) && defined(ABSL_ARCH_AARCH64)
  181. // 3. Use sysctlbyname.
  182. // Newer XNU kernels support querying all capabilities in a single
  183. // sysctlbyname.
  184. #if defined(CAP_BIT_AdvSIMD) && defined(CAP_BIT_FEAT_AES)
  185. static const absl::optional<uint64_t> caps =
  186. ReadSysctlByName<uint64_t>("hw.optional.arm.caps");
  187. if (caps.has_value()) {
  188. constexpr uint64_t kNeonAndAesCaps =
  189. (uint64_t{1} << CAP_BIT_AdvSIMD) | (uint64_t{1} << CAP_BIT_FEAT_AES);
  190. return (*caps & kNeonAndAesCaps) == kNeonAndAesCaps;
  191. }
  192. #endif
  193. // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#overview
  194. static const absl::optional<int> adv_simd =
  195. ReadSysctlByName<int>("hw.optional.AdvSIMD");
  196. if (adv_simd.value_or(0) == 0) {
  197. return false;
  198. }
  199. // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3918855
  200. static const absl::optional<int> feat_aes =
  201. ReadSysctlByName<int>("hw.optional.arm.FEAT_AES");
  202. if (feat_aes.value_or(0) == 0) {
  203. return false;
  204. }
  205. return true;
  206. #else // ABSL_INTERNAL_USE_GETAUXVAL
  207. // 4. By default, assume that the compiler default.
  208. return ABSL_HAVE_ACCELERATED_AES ? true : false;
  209. #endif
  210. // NOTE: There are some other techniques that may be worth trying:
  211. //
  212. // * Use an environment variable: ABSL_RANDOM_USE_HWAES
  213. //
  214. // * Rely on compiler-generated target-based dispatch.
  215. // Using x86/gcc it might look something like this:
  216. //
  217. // int __attribute__((target("aes"))) HasAes() { return 1; }
  218. // int __attribute__((target("default"))) HasAes() { return 0; }
  219. //
  220. // This does not work on all architecture/compiler combinations.
  221. //
  222. // * On Linux consider reading /proc/cpuinfo and/or /proc/self/auxv.
  223. // These files have lines which are easy to parse; for ARM/AARCH64 it is quite
  224. // easy to find the Features: line and extract aes / neon. Likewise for
  225. // PPC.
  226. //
  227. // * Fork a process and test for SIGILL:
  228. //
  229. // * Many architectures have instructions to read the ISA. Unfortunately
  230. // most of those require that the code is running in ring 0 /
  231. // protected-mode.
  232. //
  233. // There are several examples. e.g. Valgrind detects PPC ISA 2.07:
  234. // https://github.com/lu-zero/valgrind/blob/master/none/tests/ppc64/test_isa_2_07_part1.c
  235. //
  236. // MRS <Xt>, ID_AA64ISAR0_EL1 ; Read ID_AA64ISAR0_EL1 into Xt
  237. //
  238. // uint64_t val;
  239. // __asm __volatile("mrs %0, id_aa64isar0_el1" :"=&r" (val));
  240. //
  241. // * Use a CPUID-style heuristic database.
  242. }
  243. #if defined(__clang__)
  244. #pragma clang diagnostic pop
  245. #endif
  246. } // namespace random_internal
  247. ABSL_NAMESPACE_END
  248. } // namespace absl