19
19
20
20
#include " absl/random/internal/randen_detect.h"
21
21
22
+ #if defined(__APPLE__) && defined(__aarch64__)
23
+ #if defined(__has_include)
24
+ #if __has_include(<arm/cpu_capabilities_public.h>)
25
+ #include < arm/cpu_capabilities_public.h>
26
+ #endif
27
+ #endif
28
+ #include < sys/sysctl.h>
29
+ #include < sys/types.h>
30
+ #endif
31
+
22
32
#include < cstdint>
23
33
#include < cstring>
24
34
25
35
#include " absl/random/internal/platform.h"
36
+ #include " absl/types/optional.h" // IWYU pragma: keep
26
37
27
38
#if !defined(__UCLIBC__) && defined(__GLIBC__) && \
28
39
(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 16 ))
@@ -102,6 +113,19 @@ static uint32_t GetAuxval(uint32_t hwcap_type) {
102
113
103
114
#endif
104
115
116
+ #if defined(__APPLE__) && defined(ABSL_ARCH_AARCH64)
117
+ template <typename T>
118
+ static absl::optional<T> ReadSysctlByName (const char * name) {
119
+ T val;
120
+ size_t val_size = sizeof (T);
121
+ int ret = sysctlbyname (name, &val, &val_size, nullptr , 0 );
122
+ if (ret == -1 ) {
123
+ return std::nullopt;
124
+ }
125
+ return val;
126
+ }
127
+ #endif
128
+
105
129
namespace absl {
106
130
ABSL_NAMESPACE_BEGIN
107
131
namespace random_internal {
@@ -122,14 +146,18 @@ namespace random_internal {
122
146
//
123
147
// Fon non-x86 it is much more complicated.
124
148
//
125
- // 2. When ABSL_INTERNAL_USE_GETAUXVAL is defined, use getauxval() (either
149
+ // 2. Try to use __builtin_cpu_supports.
150
+ //
151
+ // 3. When ABSL_INTERNAL_USE_GETAUXVAL is defined, use getauxval() (either
126
152
// the direct c-library version, or the android probing version which loads
127
153
// libc), and read the hardware capability bits.
128
154
// This is based on the technique used by boringssl uses to detect
129
155
// cpu capabilities, and should allow us to enable crypto in the android
130
156
// builds where it is supported.
131
157
//
132
- // 3. Use the default for the compiler architecture.
158
+ // 4. When __APPLE__ is defined on AARCH64, use sysctlbyname().
159
+ //
160
+ // 5. Use the default for the compiler architecture.
133
161
//
134
162
135
163
bool CPUSupportsRandenHwAes () {
@@ -139,8 +167,14 @@ bool CPUSupportsRandenHwAes() {
139
167
__cpuid (reinterpret_cast <int *>(regs), 1 );
140
168
return regs[2 ] & (1 << 25 ); // AES
141
169
170
+ #elif defined(ABSL_ARCH_AARCH64) && ABSL_HAVE_BUILTIN(__builtin_cpu_supports)
171
+ // For AARCH64: Require crypto+neon
172
+ // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500f/CIHBIBBA.html
173
+ //
174
+ // __builtin_cpu_supports spells "crypt" as "aes" and "neon" as "simd".
175
+ return __builtin_cpu_supports (" aes+simd" );
142
176
#elif defined(ABSL_INTERNAL_USE_GETAUXVAL)
143
- // 2 . Use getauxval() to read the hardware bits and determine
177
+ // 3 . Use getauxval() to read the hardware bits and determine
144
178
// cpu capabilities.
145
179
146
180
#define AT_HWCAP 16
@@ -178,8 +212,36 @@ bool CPUSupportsRandenHwAes() {
178
212
return ((hwcap & kNEON ) != 0 ) && ((hwcap & kAES ) != 0 );
179
213
#endif
180
214
215
+ #elif defined(__APPLE__) && defined(ABSL_ARCH_AARCH64)
216
+ // 4. Use sysctlbyname.
217
+
218
+ // Newer XNU kernels support querying all capabilities in a single
219
+ // sysctlbyname.
220
+ #if defined(CAP_BIT_AdvSIMD) && defined(CAP_BIT_FEAT_AES)
221
+ static const absl::optional<uint64_t > caps =
222
+ ReadSysctlByName<uint64_t >(" hw.optional.arm.caps" );
223
+ if (caps.has_value ()) {
224
+ constexpr uint64_t kNeonAndAesCaps =
225
+ (uint64_t {1 } << CAP_BIT_AdvSIMD) | (uint64_t {1 } << CAP_BIT_FEAT_AES);
226
+ return (*caps & kNeonAndAesCaps ) == kNeonAndAesCaps ;
227
+ }
228
+ #endif
229
+
230
+ // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#overview
231
+ static const absl::optional<int > adv_simd =
232
+ ReadSysctlByName<int >(" hw.optional.AdvSIMD" );
233
+ if (adv_simd.value_or (0 ) == 0 ) {
234
+ return false ;
235
+ }
236
+ // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3918855
237
+ static const absl::optional<int > feat_aes =
238
+ ReadSysctlByName<int >(" hw.optional.arm.FEAT_AES" );
239
+ if (feat_aes.value_or (0 ) == 0 ) {
240
+ return false ;
241
+ }
242
+ return true ;
181
243
#else // ABSL_INTERNAL_USE_GETAUXVAL
182
- // 3 . By default, assume that the compiler default.
244
+ // 5 . By default, assume that the compiler default.
183
245
return ABSL_HAVE_ACCELERATED_AES ? true : false ;
184
246
185
247
#endif
@@ -215,9 +277,6 @@ bool CPUSupportsRandenHwAes() {
215
277
// __asm __volatile("mrs %0, id_aa64isar0_el1" :"=&r" (val));
216
278
//
217
279
// * Use a CPUID-style heuristic database.
218
- //
219
- // * On Apple (__APPLE__), AES is available on Arm v8.
220
- // https://stackoverflow.com/questions/45637888/how-to-determine-armv8-features-at-runtime-on-ios
221
280
}
222
281
223
282
#if defined(__clang__)
0 commit comments