xref: /freebsd/crypto/openssl/crypto/armcap.c (revision b077aed3)
1e71b7053SJung-uk Kim /*
2b077aed3SPierre Pronchery  * Copyright 2011-2022 The OpenSSL Project Authors. All Rights Reserved.
3e71b7053SJung-uk Kim  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
8e71b7053SJung-uk Kim  */
9e71b7053SJung-uk Kim 
101f13597dSJung-uk Kim #include <stdio.h>
111f13597dSJung-uk Kim #include <stdlib.h>
121f13597dSJung-uk Kim #include <string.h>
131f13597dSJung-uk Kim #include <setjmp.h>
141f13597dSJung-uk Kim #include <signal.h>
15e71b7053SJung-uk Kim #include <openssl/crypto.h>
16b077aed3SPierre Pronchery #ifdef __APPLE__
17b077aed3SPierre Pronchery #include <sys/sysctl.h>
18b077aed3SPierre Pronchery #endif
19e71b7053SJung-uk Kim #include "internal/cryptlib.h"
201f13597dSJung-uk Kim 
211f13597dSJung-uk Kim #include "arm_arch.h"
221f13597dSJung-uk Kim 
237bded2dbSJung-uk Kim unsigned int OPENSSL_armcap_P = 0;
24b077aed3SPierre Pronchery unsigned int OPENSSL_arm_midr = 0;
25b077aed3SPierre Pronchery unsigned int OPENSSL_armv8_rsa_neonized = 0;
261f13597dSJung-uk Kim 
277bded2dbSJung-uk Kim #if __ARM_MAX_ARCH__<7
OPENSSL_cpuid_setup(void)287bded2dbSJung-uk Kim void OPENSSL_cpuid_setup(void)
297bded2dbSJung-uk Kim {
307bded2dbSJung-uk Kim }
317bded2dbSJung-uk Kim 
OPENSSL_rdtsc(void)32e71b7053SJung-uk Kim uint32_t OPENSSL_rdtsc(void)
337bded2dbSJung-uk Kim {
347bded2dbSJung-uk Kim     return 0;
357bded2dbSJung-uk Kim }
367bded2dbSJung-uk Kim #else
371f13597dSJung-uk Kim static sigset_t all_masked;
381f13597dSJung-uk Kim 
391f13597dSJung-uk Kim static sigjmp_buf ill_jmp;
ill_handler(int sig)406f9291ceSJung-uk Kim static void ill_handler(int sig)
416f9291ceSJung-uk Kim {
426f9291ceSJung-uk Kim     siglongjmp(ill_jmp, sig);
436f9291ceSJung-uk Kim }
441f13597dSJung-uk Kim 
451f13597dSJung-uk Kim /*
461f13597dSJung-uk Kim  * Following subroutines could have been inlined, but it's not all
471f13597dSJung-uk Kim  * ARM compilers support inline assembler...
481f13597dSJung-uk Kim  */
491f13597dSJung-uk Kim void _armv7_neon_probe(void);
507bded2dbSJung-uk Kim void _armv8_aes_probe(void);
517bded2dbSJung-uk Kim void _armv8_sha1_probe(void);
527bded2dbSJung-uk Kim void _armv8_sha256_probe(void);
537bded2dbSJung-uk Kim void _armv8_pmull_probe(void);
54e71b7053SJung-uk Kim # ifdef __aarch64__
55e71b7053SJung-uk Kim void _armv8_sha512_probe(void);
56b077aed3SPierre Pronchery unsigned int _armv8_cpuid_probe(void);
57e71b7053SJung-uk Kim # endif
58e71b7053SJung-uk Kim uint32_t _armv7_tick(void);
591f13597dSJung-uk Kim 
OPENSSL_rdtsc(void)60e71b7053SJung-uk Kim uint32_t OPENSSL_rdtsc(void)
611f13597dSJung-uk Kim {
62de78d5d8SJung-uk Kim     if (OPENSSL_armcap_P & ARMV7_TICK)
631f13597dSJung-uk Kim         return _armv7_tick();
641f13597dSJung-uk Kim     else
651f13597dSJung-uk Kim         return 0;
661f13597dSJung-uk Kim }
671f13597dSJung-uk Kim 
68e71b7053SJung-uk Kim # if defined(__GNUC__) && __GNUC__>=2
69e71b7053SJung-uk Kim void OPENSSL_cpuid_setup(void) __attribute__ ((constructor));
70e71b7053SJung-uk Kim # endif
716935a639SJung-uk Kim 
726935a639SJung-uk Kim # if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
736935a639SJung-uk Kim #  if __GLIBC_PREREQ(2, 16)
746935a639SJung-uk Kim #   include <sys/auxv.h>
756935a639SJung-uk Kim #   define OSSL_IMPLEMENT_GETAUXVAL
766935a639SJung-uk Kim #  endif
779a3ae0cdSJung-uk Kim # elif defined(__ANDROID_API__)
789a3ae0cdSJung-uk Kim /* see https://developer.android.google.cn/ndk/guides/cpu-features */
799a3ae0cdSJung-uk Kim #  if __ANDROID_API__ >= 18
809a3ae0cdSJung-uk Kim #   include <sys/auxv.h>
819a3ae0cdSJung-uk Kim #   define OSSL_IMPLEMENT_GETAUXVAL
829a3ae0cdSJung-uk Kim #  endif
831f13597dSJung-uk Kim # endif
8488e852c0SJung-uk Kim # if defined(__FreeBSD__)
8588e852c0SJung-uk Kim #  include <sys/param.h>
8688e852c0SJung-uk Kim #  if __FreeBSD_version >= 1200000
8788e852c0SJung-uk Kim #   include <sys/auxv.h>
8888e852c0SJung-uk Kim #   define OSSL_IMPLEMENT_GETAUXVAL
8988e852c0SJung-uk Kim 
getauxval(unsigned long key)9088e852c0SJung-uk Kim static unsigned long getauxval(unsigned long key)
9188e852c0SJung-uk Kim {
9288e852c0SJung-uk Kim   unsigned long val = 0ul;
9388e852c0SJung-uk Kim 
9488e852c0SJung-uk Kim   if (elf_aux_info((int)key, &val, sizeof(val)) != 0)
9588e852c0SJung-uk Kim     return 0ul;
9688e852c0SJung-uk Kim 
9788e852c0SJung-uk Kim   return val;
9888e852c0SJung-uk Kim }
9988e852c0SJung-uk Kim #  endif
10088e852c0SJung-uk Kim # endif
1017bded2dbSJung-uk Kim 
1027bded2dbSJung-uk Kim /*
1039a3ae0cdSJung-uk Kim  * Android: according to https://developer.android.com/ndk/guides/cpu-features,
1049a3ae0cdSJung-uk Kim  * getauxval is supported starting with API level 18
1059a3ae0cdSJung-uk Kim  */
1069a3ae0cdSJung-uk Kim #  if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 18
1079a3ae0cdSJung-uk Kim #   include <sys/auxv.h>
1089a3ae0cdSJung-uk Kim #   define OSSL_IMPLEMENT_GETAUXVAL
1099a3ae0cdSJung-uk Kim #  endif
1109a3ae0cdSJung-uk Kim 
1119a3ae0cdSJung-uk Kim /*
112e71b7053SJung-uk Kim  * ARM puts the feature bits for Crypto Extensions in AT_HWCAP2, whereas
1137bded2dbSJung-uk Kim  * AArch64 used AT_HWCAP.
1147bded2dbSJung-uk Kim  */
115d9bb7987SAllan Jude # ifndef AT_HWCAP
116d9bb7987SAllan Jude #  define AT_HWCAP               16
117d9bb7987SAllan Jude # endif
118d9bb7987SAllan Jude # ifndef AT_HWCAP2
119d9bb7987SAllan Jude #  define AT_HWCAP2              26
120d9bb7987SAllan Jude # endif
1217bded2dbSJung-uk Kim # if defined(__arm__) || defined (__arm)
122d9bb7987SAllan Jude #  define HWCAP                  AT_HWCAP
1237bded2dbSJung-uk Kim #  define HWCAP_NEON             (1 << 12)
1247bded2dbSJung-uk Kim 
125d9bb7987SAllan Jude #  define HWCAP_CE               AT_HWCAP2
1267bded2dbSJung-uk Kim #  define HWCAP_CE_AES           (1 << 0)
1277bded2dbSJung-uk Kim #  define HWCAP_CE_PMULL         (1 << 1)
1287bded2dbSJung-uk Kim #  define HWCAP_CE_SHA1          (1 << 2)
1297bded2dbSJung-uk Kim #  define HWCAP_CE_SHA256        (1 << 3)
1307bded2dbSJung-uk Kim # elif defined(__aarch64__)
131d9bb7987SAllan Jude #  define HWCAP                  AT_HWCAP
1327bded2dbSJung-uk Kim #  define HWCAP_NEON             (1 << 1)
1337bded2dbSJung-uk Kim 
1347bded2dbSJung-uk Kim #  define HWCAP_CE               HWCAP
1357bded2dbSJung-uk Kim #  define HWCAP_CE_AES           (1 << 3)
1367bded2dbSJung-uk Kim #  define HWCAP_CE_PMULL         (1 << 4)
1377bded2dbSJung-uk Kim #  define HWCAP_CE_SHA1          (1 << 5)
1387bded2dbSJung-uk Kim #  define HWCAP_CE_SHA256        (1 << 6)
139b077aed3SPierre Pronchery #  define HWCAP_CPUID            (1 << 11)
140e71b7053SJung-uk Kim #  define HWCAP_CE_SHA512        (1 << 21)
1417bded2dbSJung-uk Kim # endif
1427bded2dbSJung-uk Kim 
OPENSSL_cpuid_setup(void)1431f13597dSJung-uk Kim void OPENSSL_cpuid_setup(void)
1441f13597dSJung-uk Kim {
145e71b7053SJung-uk Kim     const char *e;
1461f13597dSJung-uk Kim     struct sigaction ill_oact, ill_act;
1471f13597dSJung-uk Kim     sigset_t oset;
1481f13597dSJung-uk Kim     static int trigger = 0;
1491f13597dSJung-uk Kim 
1506f9291ceSJung-uk Kim     if (trigger)
1516f9291ceSJung-uk Kim         return;
1521f13597dSJung-uk Kim     trigger = 1;
1531f13597dSJung-uk Kim 
154b077aed3SPierre Pronchery     OPENSSL_armcap_P = 0;
155b077aed3SPierre Pronchery 
1566f9291ceSJung-uk Kim     if ((e = getenv("OPENSSL_armcap"))) {
1577bded2dbSJung-uk Kim         OPENSSL_armcap_P = (unsigned int)strtoul(e, NULL, 0);
1581f13597dSJung-uk Kim         return;
1591f13597dSJung-uk Kim     }
1601f13597dSJung-uk Kim 
161b077aed3SPierre Pronchery # if defined(__APPLE__)
162b077aed3SPierre Pronchery #   if !defined(__aarch64__)
163e71b7053SJung-uk Kim     /*
164e71b7053SJung-uk Kim      * Capability probing by catching SIGILL appears to be problematic
165e71b7053SJung-uk Kim      * on iOS. But since Apple universe is "monocultural", it's actually
166e71b7053SJung-uk Kim      * possible to simply set pre-defined processor capability mask.
167e71b7053SJung-uk Kim      */
168e71b7053SJung-uk Kim     if (1) {
169e71b7053SJung-uk Kim         OPENSSL_armcap_P = ARMV7_NEON;
170e71b7053SJung-uk Kim         return;
171e71b7053SJung-uk Kim     }
172e71b7053SJung-uk Kim     /*
173e71b7053SJung-uk Kim      * One could do same even for __aarch64__ iOS builds. It's not done
174e71b7053SJung-uk Kim      * exclusively for reasons of keeping code unified across platforms.
175e71b7053SJung-uk Kim      * Unified code works because it never triggers SIGILL on Apple
176e71b7053SJung-uk Kim      * devices...
177e71b7053SJung-uk Kim      */
178b077aed3SPierre Pronchery #   else
179b077aed3SPierre Pronchery     {
180b077aed3SPierre Pronchery         unsigned int sha512;
181b077aed3SPierre Pronchery         size_t len = sizeof(sha512);
182e71b7053SJung-uk Kim 
183b077aed3SPierre Pronchery         if (sysctlbyname("hw.optional.armv8_2_sha512", &sha512, &len, NULL, 0) == 0 && sha512 == 1)
184b077aed3SPierre Pronchery             OPENSSL_armcap_P |= ARMV8_SHA512;
185b077aed3SPierre Pronchery     }
186b077aed3SPierre Pronchery #   endif
187b077aed3SPierre Pronchery # endif
1881f13597dSJung-uk Kim 
1896935a639SJung-uk Kim # ifdef OSSL_IMPLEMENT_GETAUXVAL
1907bded2dbSJung-uk Kim     if (getauxval(HWCAP) & HWCAP_NEON) {
1917bded2dbSJung-uk Kim         unsigned long hwcap = getauxval(HWCAP_CE);
1927bded2dbSJung-uk Kim 
1937bded2dbSJung-uk Kim         OPENSSL_armcap_P |= ARMV7_NEON;
1947bded2dbSJung-uk Kim 
1957bded2dbSJung-uk Kim         if (hwcap & HWCAP_CE_AES)
1967bded2dbSJung-uk Kim             OPENSSL_armcap_P |= ARMV8_AES;
1977bded2dbSJung-uk Kim 
1987bded2dbSJung-uk Kim         if (hwcap & HWCAP_CE_PMULL)
1997bded2dbSJung-uk Kim             OPENSSL_armcap_P |= ARMV8_PMULL;
2007bded2dbSJung-uk Kim 
2017bded2dbSJung-uk Kim         if (hwcap & HWCAP_CE_SHA1)
2027bded2dbSJung-uk Kim             OPENSSL_armcap_P |= ARMV8_SHA1;
2037bded2dbSJung-uk Kim 
2047bded2dbSJung-uk Kim         if (hwcap & HWCAP_CE_SHA256)
2057bded2dbSJung-uk Kim             OPENSSL_armcap_P |= ARMV8_SHA256;
206e71b7053SJung-uk Kim 
207e71b7053SJung-uk Kim #  ifdef __aarch64__
208e71b7053SJung-uk Kim         if (hwcap & HWCAP_CE_SHA512)
209e71b7053SJung-uk Kim             OPENSSL_armcap_P |= ARMV8_SHA512;
210b077aed3SPierre Pronchery 
211b077aed3SPierre Pronchery         if (hwcap & HWCAP_CPUID)
212b077aed3SPierre Pronchery             OPENSSL_armcap_P |= ARMV8_CPUID;
213e71b7053SJung-uk Kim #  endif
2147bded2dbSJung-uk Kim     }
2156935a639SJung-uk Kim # endif
2166935a639SJung-uk Kim 
2176935a639SJung-uk Kim     sigfillset(&all_masked);
2186935a639SJung-uk Kim     sigdelset(&all_masked, SIGILL);
2196935a639SJung-uk Kim     sigdelset(&all_masked, SIGTRAP);
2206935a639SJung-uk Kim     sigdelset(&all_masked, SIGFPE);
2216935a639SJung-uk Kim     sigdelset(&all_masked, SIGBUS);
2226935a639SJung-uk Kim     sigdelset(&all_masked, SIGSEGV);
2236935a639SJung-uk Kim 
2246935a639SJung-uk Kim     memset(&ill_act, 0, sizeof(ill_act));
2256935a639SJung-uk Kim     ill_act.sa_handler = ill_handler;
2266935a639SJung-uk Kim     ill_act.sa_mask = all_masked;
2276935a639SJung-uk Kim 
2286935a639SJung-uk Kim     sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset);
2296935a639SJung-uk Kim     sigaction(SIGILL, &ill_act, &ill_oact);
2306935a639SJung-uk Kim 
2316935a639SJung-uk Kim     /* If we used getauxval, we already have all the values */
2326935a639SJung-uk Kim # ifndef OSSL_IMPLEMENT_GETAUXVAL
2336935a639SJung-uk Kim     if (sigsetjmp(ill_jmp, 1) == 0) {
2341f13597dSJung-uk Kim         _armv7_neon_probe();
2351f13597dSJung-uk Kim         OPENSSL_armcap_P |= ARMV7_NEON;
2367bded2dbSJung-uk Kim         if (sigsetjmp(ill_jmp, 1) == 0) {
2377bded2dbSJung-uk Kim             _armv8_pmull_probe();
2387bded2dbSJung-uk Kim             OPENSSL_armcap_P |= ARMV8_PMULL | ARMV8_AES;
2397bded2dbSJung-uk Kim         } else if (sigsetjmp(ill_jmp, 1) == 0) {
2407bded2dbSJung-uk Kim             _armv8_aes_probe();
2417bded2dbSJung-uk Kim             OPENSSL_armcap_P |= ARMV8_AES;
2427bded2dbSJung-uk Kim         }
2437bded2dbSJung-uk Kim         if (sigsetjmp(ill_jmp, 1) == 0) {
2447bded2dbSJung-uk Kim             _armv8_sha1_probe();
2457bded2dbSJung-uk Kim             OPENSSL_armcap_P |= ARMV8_SHA1;
2467bded2dbSJung-uk Kim         }
2477bded2dbSJung-uk Kim         if (sigsetjmp(ill_jmp, 1) == 0) {
2487bded2dbSJung-uk Kim             _armv8_sha256_probe();
2497bded2dbSJung-uk Kim             OPENSSL_armcap_P |= ARMV8_SHA256;
2507bded2dbSJung-uk Kim         }
251e71b7053SJung-uk Kim #  if defined(__aarch64__) && !defined(__APPLE__)
252e71b7053SJung-uk Kim         if (sigsetjmp(ill_jmp, 1) == 0) {
253e71b7053SJung-uk Kim             _armv8_sha512_probe();
254e71b7053SJung-uk Kim             OPENSSL_armcap_P |= ARMV8_SHA512;
255e71b7053SJung-uk Kim         }
256e71b7053SJung-uk Kim #  endif
2571f13597dSJung-uk Kim     }
2586935a639SJung-uk Kim # endif
2596935a639SJung-uk Kim 
260b077aed3SPierre Pronchery     /*
261b077aed3SPierre Pronchery      * Probing for ARMV7_TICK is known to produce unreliable results,
262b077aed3SPierre Pronchery      * so we will only use the feature when the user explicitly enables
263b077aed3SPierre Pronchery      * it with OPENSSL_armcap.
264b077aed3SPierre Pronchery      */
2651f13597dSJung-uk Kim 
2661f13597dSJung-uk Kim     sigaction(SIGILL, &ill_oact, NULL);
2671f13597dSJung-uk Kim     sigprocmask(SIG_SETMASK, &oset, NULL);
268b077aed3SPierre Pronchery 
269b077aed3SPierre Pronchery # ifdef __aarch64__
270b077aed3SPierre Pronchery     if (OPENSSL_armcap_P & ARMV8_CPUID)
271b077aed3SPierre Pronchery         OPENSSL_arm_midr = _armv8_cpuid_probe();
272b077aed3SPierre Pronchery 
273b077aed3SPierre Pronchery     if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) ||
274b077aed3SPierre Pronchery          MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N1)) &&
275b077aed3SPierre Pronchery         (OPENSSL_armcap_P & ARMV7_NEON)) {
276b077aed3SPierre Pronchery             OPENSSL_armv8_rsa_neonized = 1;
277b077aed3SPierre Pronchery     }
278b077aed3SPierre Pronchery # endif
2791f13597dSJung-uk Kim }
2807bded2dbSJung-uk Kim #endif
281