VirtualBox

source: vbox/trunk/src/libs/openssl-3.1.5/crypto/armcap.c

Last change on this file was 104078, checked in by vboxsync, 2 months ago

openssl-3.1.5: Applied and adjusted our OpenSSL changes to 3.1.4. bugref:10638

File size: 12.7 KB
Line 
1/*
2 * Copyright 2011-2023 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <openssl/crypto.h>
14#ifdef __APPLE__
15#include <sys/sysctl.h>
16#else
17#include <setjmp.h>
18#include <signal.h>
19#endif
20#ifdef RT_OS_DARWIN /* VBOX */
21# include <pthread.h> /* VBOX */
22# define sigprocmask pthread_sigmask /* On xnu sigprocmask works on the process, not the calling thread as elsewhere. */
23#endif /* VBOX */
24#include "internal/cryptlib.h"
25#ifdef _WIN32
26#include <windows.h>
27#else
28#include <unistd.h>
29#endif
30#include "arm_arch.h"
31
32unsigned int OPENSSL_armcap_P = 0;
33unsigned int OPENSSL_arm_midr = 0;
34unsigned int OPENSSL_armv8_rsa_neonized = 0;
35
36#ifdef _WIN32
37void OPENSSL_cpuid_setup(void)
38{
39 OPENSSL_armcap_P |= ARMV7_NEON;
40 OPENSSL_armv8_rsa_neonized = 1;
41 if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)) {
42 // These are all covered by one call in Windows
43 OPENSSL_armcap_P |= ARMV8_AES;
44 OPENSSL_armcap_P |= ARMV8_PMULL;
45 OPENSSL_armcap_P |= ARMV8_SHA1;
46 OPENSSL_armcap_P |= ARMV8_SHA256;
47 }
48}
49
50uint32_t OPENSSL_rdtsc(void)
51{
52 return 0;
53}
54#elif __ARM_MAX_ARCH__ < 7
55void OPENSSL_cpuid_setup(void)
56{
57}
58
59uint32_t OPENSSL_rdtsc(void)
60{
61 return 0;
62}
63#else /* !_WIN32 && __ARM_MAX_ARCH__ >= 7 */
64
65 /* 3 ways of handling things here: __APPLE__, getauxval() or SIGILL detect */
66
67 /* First determine if getauxval() is available (OSSL_IMPLEMENT_GETAUXVAL) */
68
69# if defined(__GNUC__) && __GNUC__>=2
70void OPENSSL_cpuid_setup(void) __attribute__ ((constructor));
71# endif
72
73# if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
74# if __GLIBC_PREREQ(2, 16)
75# include <sys/auxv.h>
76# define OSSL_IMPLEMENT_GETAUXVAL
77# endif
78# elif defined(__ANDROID_API__)
79/* see https://developer.android.google.cn/ndk/guides/cpu-features */
80# if __ANDROID_API__ >= 18
81# include <sys/auxv.h>
82# define OSSL_IMPLEMENT_GETAUXVAL
83# endif
84# endif
85# if defined(__FreeBSD__)
86# include <sys/param.h>
87# if __FreeBSD_version >= 1200000
88# include <sys/auxv.h>
89# define OSSL_IMPLEMENT_GETAUXVAL
90
91static unsigned long getauxval(unsigned long key)
92{
93 unsigned long val = 0ul;
94
95 if (elf_aux_info((int)key, &val, sizeof(val)) != 0)
96 return 0ul;
97
98 return val;
99}
100# endif
101# endif
102
103/*
104 * Android: according to https://developer.android.com/ndk/guides/cpu-features,
105 * getauxval is supported starting with API level 18
106 */
107# if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 18
108# include <sys/auxv.h>
109# define OSSL_IMPLEMENT_GETAUXVAL
110# endif
111
112/*
113 * ARM puts the feature bits for Crypto Extensions in AT_HWCAP2, whereas
114 * AArch64 used AT_HWCAP.
115 */
116# ifndef AT_HWCAP
117# define AT_HWCAP 16
118# endif
119# ifndef AT_HWCAP2
120# define AT_HWCAP2 26
121# endif
122# if defined(__arm__) || defined (__arm)
123# define OSSL_HWCAP AT_HWCAP
124# define OSSL_HWCAP_NEON (1 << 12)
125
126# define OSSL_HWCAP_CE AT_HWCAP2
127# define OSSL_HWCAP_CE_AES (1 << 0)
128# define OSSL_HWCAP_CE_PMULL (1 << 1)
129# define OSSL_HWCAP_CE_SHA1 (1 << 2)
130# define OSSL_HWCAP_CE_SHA256 (1 << 3)
131# elif defined(__aarch64__)
132# define OSSL_HWCAP AT_HWCAP
133# define OSSL_HWCAP_NEON (1 << 1)
134
135# define OSSL_HWCAP_CE AT_HWCAP
136# define OSSL_HWCAP_CE_AES (1 << 3)
137# define OSSL_HWCAP_CE_PMULL (1 << 4)
138# define OSSL_HWCAP_CE_SHA1 (1 << 5)
139# define OSSL_HWCAP_CE_SHA256 (1 << 6)
140# define OSSL_HWCAP_CPUID (1 << 11)
141# define OSSL_HWCAP_SHA3 (1 << 17)
142# define OSSL_HWCAP_CE_SM3 (1 << 18)
143# define OSSL_HWCAP_CE_SM4 (1 << 19)
144# define OSSL_HWCAP_CE_SHA512 (1 << 21)
145# define OSSL_HWCAP_SVE (1 << 22)
146 /* AT_HWCAP2 */
147# define OSSL_HWCAP2 26
148# define OSSL_HWCAP2_SVE2 (1 << 1)
149# define OSSL_HWCAP2_RNG (1 << 16)
150# endif
151
152uint32_t _armv7_tick(void);
153
154uint32_t OPENSSL_rdtsc(void)
155{
156 if (OPENSSL_armcap_P & ARMV7_TICK)
157 return _armv7_tick();
158 else
159 return 0;
160}
161
162# ifdef __aarch64__
163size_t OPENSSL_rndr_asm(unsigned char *buf, size_t len);
164size_t OPENSSL_rndrrs_asm(unsigned char *buf, size_t len);
165
166size_t OPENSSL_rndr_bytes(unsigned char *buf, size_t len);
167size_t OPENSSL_rndrrs_bytes(unsigned char *buf, size_t len);
168
169static size_t OPENSSL_rndr_wrapper(size_t (*func)(unsigned char *, size_t), unsigned char *buf, size_t len)
170{
171 size_t buffer_size = 0;
172 int i;
173
174 for (i = 0; i < 8; i++) {
175 buffer_size = func(buf, len);
176 if (buffer_size == len)
177 break;
178 usleep(5000); /* 5000 microseconds (5 milliseconds) */
179 }
180 return buffer_size;
181}
182
183size_t OPENSSL_rndr_bytes(unsigned char *buf, size_t len)
184{
185 return OPENSSL_rndr_wrapper(OPENSSL_rndr_asm, buf, len);
186}
187
188size_t OPENSSL_rndrrs_bytes(unsigned char *buf, size_t len)
189{
190 return OPENSSL_rndr_wrapper(OPENSSL_rndrrs_asm, buf, len);
191}
192# endif
193
194# if !defined(__APPLE__) && !defined(OSSL_IMPLEMENT_GETAUXVAL)
195static sigset_t all_masked;
196
197static sigjmp_buf ill_jmp;
198static void ill_handler(int sig)
199{
200 siglongjmp(ill_jmp, sig);
201}
202
203/*
204 * Following subroutines could have been inlined, but not all
205 * ARM compilers support inline assembler, and we'd then have to
206 * worry about the compiler optimising out the detection code...
207 */
208void _armv7_neon_probe(void);
209void _armv8_aes_probe(void);
210void _armv8_sha1_probe(void);
211void _armv8_sha256_probe(void);
212void _armv8_pmull_probe(void);
213# ifdef __aarch64__
214void _armv8_sm3_probe(void);
215void _armv8_sm4_probe(void);
216void _armv8_sha512_probe(void);
217void _armv8_eor3_probe(void);
218void _armv8_sve_probe(void);
219void _armv8_sve2_probe(void);
220void _armv8_rng_probe(void);
221# endif
222# endif /* !__APPLE__ && !OSSL_IMPLEMENT_GETAUXVAL */
223
224/* We only call _armv8_cpuid_probe() if (OPENSSL_armcap_P & ARMV8_CPUID) != 0 */
225unsigned int _armv8_cpuid_probe(void);
226
227# if defined(__APPLE__)
228/*
229 * Checks the specified integer sysctl, returning `value` if it's 1, otherwise returning 0.
230 */
231static unsigned int sysctl_query(const char *name, unsigned int value)
232{
233 unsigned int sys_value = 0;
234 size_t len = sizeof(sys_value);
235
236 return (sysctlbyname(name, &sys_value, &len, NULL, 0) == 0 && sys_value == 1) ? value : 0;
237}
238# elif !defined(OSSL_IMPLEMENT_GETAUXVAL)
239/*
240 * Calls a provided probe function, which may SIGILL. If it doesn't, return `value`, otherwise return 0.
241 */
242static unsigned int arm_probe_for(void (*probe)(void), volatile unsigned int value)
243{
244 if (sigsetjmp(ill_jmp, 1) == 0) {
245 probe();
246 return value;
247 } else {
248 /* The probe function gave us SIGILL */
249 return 0;
250 }
251}
252# endif
253
254void OPENSSL_cpuid_setup(void)
255{
256 const char *e;
257# if !defined(__APPLE__) && !defined(OSSL_IMPLEMENT_GETAUXVAL)
258 struct sigaction ill_oact, ill_act;
259 sigset_t oset;
260# endif
261 static int trigger = 0;
262
263 if (trigger)
264 return;
265 trigger = 1;
266
267 OPENSSL_armcap_P = 0;
268
269 if ((e = getenv("OPENSSL_armcap"))) {
270 OPENSSL_armcap_P = (unsigned int)strtoul(e, NULL, 0);
271 return;
272 }
273
274# if defined(__APPLE__)
275# if !defined(__aarch64__)
276 /*
277 * Capability probing by catching SIGILL appears to be problematic
278 * on iOS. But since Apple universe is "monocultural", it's actually
279 * possible to simply set pre-defined processor capability mask.
280 */
281 if (1) {
282 OPENSSL_armcap_P = ARMV7_NEON;
283 return;
284 }
285# else
286 {
287 /*
288 * From
289 * https://github.com/llvm/llvm-project/blob/412237dcd07e5a2afbb1767858262a5f037149a3/llvm/lib/Target/AArch64/AArch64.td#L719
290 * all of these have been available on 64-bit Apple Silicon from the
291 * beginning (the A7).
292 */
293 OPENSSL_armcap_P |= ARMV7_NEON | ARMV8_PMULL | ARMV8_AES | ARMV8_SHA1 | ARMV8_SHA256;
294
295 /* More recent extensions are indicated by sysctls */
296 OPENSSL_armcap_P |= sysctl_query("hw.optional.armv8_2_sha512", ARMV8_SHA512);
297 OPENSSL_armcap_P |= sysctl_query("hw.optional.armv8_2_sha3", ARMV8_SHA3);
298
299 if (OPENSSL_armcap_P & ARMV8_SHA3) {
300 char uarch[64];
301
302 size_t len = sizeof(uarch);
303 if ((sysctlbyname("machdep.cpu.brand_string", uarch, &len, NULL, 0) == 0) &&
304 ((strncmp(uarch, "Apple M1", 8) == 0) ||
305 (strncmp(uarch, "Apple M2", 8) == 0))) {
306 OPENSSL_armcap_P |= ARMV8_UNROLL8_EOR3;
307 }
308 }
309 }
310# endif /* __aarch64__ */
311
312# elif defined(OSSL_IMPLEMENT_GETAUXVAL)
313
314 if (getauxval(OSSL_HWCAP) & OSSL_HWCAP_NEON) {
315 unsigned long hwcap = getauxval(OSSL_HWCAP_CE);
316
317 OPENSSL_armcap_P |= ARMV7_NEON;
318
319 if (hwcap & OSSL_HWCAP_CE_AES)
320 OPENSSL_armcap_P |= ARMV8_AES;
321
322 if (hwcap & OSSL_HWCAP_CE_PMULL)
323 OPENSSL_armcap_P |= ARMV8_PMULL;
324
325 if (hwcap & OSSL_HWCAP_CE_SHA1)
326 OPENSSL_armcap_P |= ARMV8_SHA1;
327
328 if (hwcap & OSSL_HWCAP_CE_SHA256)
329 OPENSSL_armcap_P |= ARMV8_SHA256;
330
331# ifdef __aarch64__
332 if (hwcap & OSSL_HWCAP_CE_SM4)
333 OPENSSL_armcap_P |= ARMV8_SM4;
334
335 if (hwcap & OSSL_HWCAP_CE_SHA512)
336 OPENSSL_armcap_P |= ARMV8_SHA512;
337
338 if (hwcap & OSSL_HWCAP_CPUID)
339 OPENSSL_armcap_P |= ARMV8_CPUID;
340
341 if (hwcap & OSSL_HWCAP_CE_SM3)
342 OPENSSL_armcap_P |= ARMV8_SM3;
343 if (hwcap & OSSL_HWCAP_SHA3)
344 OPENSSL_armcap_P |= ARMV8_SHA3;
345# endif
346 }
347# ifdef __aarch64__
348 if (getauxval(OSSL_HWCAP) & OSSL_HWCAP_SVE)
349 OPENSSL_armcap_P |= ARMV8_SVE;
350
351 if (getauxval(OSSL_HWCAP2) & OSSL_HWCAP2_SVE2)
352 OPENSSL_armcap_P |= ARMV8_SVE2;
353
354 if (getauxval(OSSL_HWCAP2) & OSSL_HWCAP2_RNG)
355 OPENSSL_armcap_P |= ARMV8_RNG;
356# endif
357
358# else /* !__APPLE__ && !OSSL_IMPLEMENT_GETAUXVAL */
359
360 /* If all else fails, do brute force SIGILL-based feature detection */
361
362 sigfillset(&all_masked);
363 sigdelset(&all_masked, SIGILL);
364 sigdelset(&all_masked, SIGTRAP);
365 sigdelset(&all_masked, SIGFPE);
366 sigdelset(&all_masked, SIGBUS);
367 sigdelset(&all_masked, SIGSEGV);
368
369 memset(&ill_act, 0, sizeof(ill_act));
370 ill_act.sa_handler = ill_handler;
371 ill_act.sa_mask = all_masked;
372
373 sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset);
374 sigaction(SIGILL, &ill_act, &ill_oact);
375
376 OPENSSL_armcap_P |= arm_probe_for(_armv7_neon_probe, ARMV7_NEON);
377
378 if (OPENSSL_armcap_P & ARMV7_NEON) {
379
380 OPENSSL_armcap_P |= arm_probe_for(_armv8_pmull_probe, ARMV8_PMULL | ARMV8_AES);
381 if (!(OPENSSL_armcap_P & ARMV8_AES)) {
382 OPENSSL_armcap_P |= arm_probe_for(_armv8_aes_probe, ARMV8_AES);
383 }
384
385 OPENSSL_armcap_P |= arm_probe_for(_armv8_sha1_probe, ARMV8_SHA1);
386 OPENSSL_armcap_P |= arm_probe_for(_armv8_sha256_probe, ARMV8_SHA256);
387
388# if defined(__aarch64__)
389 OPENSSL_armcap_P |= arm_probe_for(_armv8_sm3_probe, ARMV8_SM3);
390 OPENSSL_armcap_P |= arm_probe_for(_armv8_sm4_probe, ARMV8_SM4);
391 OPENSSL_armcap_P |= arm_probe_for(_armv8_sha512_probe, ARMV8_SHA512);
392 OPENSSL_armcap_P |= arm_probe_for(_armv8_eor3_probe, ARMV8_SHA3);
393# endif
394 }
395# ifdef __aarch64__
396 OPENSSL_armcap_P |= arm_probe_for(_armv8_sve_probe, ARMV8_SVE);
397 OPENSSL_armcap_P |= arm_probe_for(_armv8_sve2_probe, ARMV8_SVE2);
398 OPENSSL_armcap_P |= arm_probe_for(_armv8_rng_probe, ARMV8_RNG);
399# endif
400
401 /*
402 * Probing for ARMV7_TICK is known to produce unreliable results,
403 * so we only use the feature when the user explicitly enables it
404 * with OPENSSL_armcap.
405 */
406
407 sigaction(SIGILL, &ill_oact, NULL);
408 sigprocmask(SIG_SETMASK, &oset, NULL);
409
410# endif /* __APPLE__, OSSL_IMPLEMENT_GETAUXVAL */
411
412# ifdef __aarch64__
413 if (OPENSSL_armcap_P & ARMV8_CPUID)
414 OPENSSL_arm_midr = _armv8_cpuid_probe();
415
416 if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) ||
417 MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N1)) &&
418 (OPENSSL_armcap_P & ARMV7_NEON)) {
419 OPENSSL_armv8_rsa_neonized = 1;
420 }
421 if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V1) ||
422 MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N2) ||
423 MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V2)) &&
424 (OPENSSL_armcap_P & ARMV8_SHA3))
425 OPENSSL_armcap_P |= ARMV8_UNROLL8_EOR3;
426# endif
427}
428#endif /* _WIN32, __ARM_MAX_ARCH__ >= 7 */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use