1 /* Copyright (c) 2014, Google Inc. 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14 15 #include <openssl/cpu.h> 16 17 #if (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) && \ 18 !defined(OPENSSL_STATIC_ARMCAP) 19 20 #include <inttypes.h> 21 #include <string.h> 22 23 #include <setjmp.h> 24 #include <signal.h> 25 26 #include <openssl/arm_arch.h> 27 28 29 /* We can't include <sys/auxv.h> because the Android SDK version against which 30 * Chromium builds is too old to have it. Instead we define all the constants 31 * that we need and have a weak pointer to getauxval. */ 32 33 unsigned long getauxval(unsigned long type) __attribute__((weak)); 34 35 extern uint32_t OPENSSL_armcap_P; 36 37 char CRYPTO_is_NEON_capable_at_runtime(void) { 38 return (OPENSSL_armcap_P & ARMV7_NEON) != 0; 39 } 40 41 static char g_set_neon_called = 0; 42 43 void CRYPTO_set_NEON_capable(char neon_capable) { 44 g_set_neon_called = 1; 45 46 if (neon_capable) { 47 OPENSSL_armcap_P |= ARMV7_NEON; 48 } else { 49 OPENSSL_armcap_P &= ~ARMV7_NEON; 50 } 51 } 52 53 char CRYPTO_is_NEON_functional(void) { 54 static const uint32_t kWantFlags = ARMV7_NEON | ARMV7_NEON_FUNCTIONAL; 55 return (OPENSSL_armcap_P & kWantFlags) == kWantFlags; 56 } 57 58 void CRYPTO_set_NEON_functional(char neon_functional) { 59 if (neon_functional) { 60 OPENSSL_armcap_P |= ARMV7_NEON_FUNCTIONAL; 61 } else { 62 OPENSSL_armcap_P &= ~ARMV7_NEON_FUNCTIONAL; 63 } 64 } 65 66 int CRYPTO_is_ARMv8_AES_capable(void) { 67 return (OPENSSL_armcap_P & ARMV8_AES) != 0; 68 } 69 70 int CRYPTO_is_ARMv8_PMULL_capable(void) { 71 return (OPENSSL_armcap_P & ARMV8_PMULL) != 0; 72 } 73 74 #if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_ARM) 75 76 static sigjmp_buf sigill_jmp; 77 78 static void sigill_handler(int signal) { 79 siglongjmp(sigill_jmp, signal); 80 } 81 82 void CRYPTO_arm_neon_probe(void); 83 84 // probe_for_NEON returns 1 if a NEON instruction runs successfully. Because 85 // getauxval doesn't exist on Android until Jelly Bean, supporting NEON on 86 // older devices requires this. 87 static int probe_for_NEON(void) { 88 int supported = 0; 89 90 sigset_t sigmask; 91 sigfillset(&sigmask); 92 sigdelset(&sigmask, SIGILL); 93 sigdelset(&sigmask, SIGTRAP); 94 sigdelset(&sigmask, SIGFPE); 95 sigdelset(&sigmask, SIGBUS); 96 sigdelset(&sigmask, SIGSEGV); 97 98 struct sigaction sigill_original_action, sigill_action; 99 memset(&sigill_action, 0, sizeof(sigill_action)); 100 sigill_action.sa_handler = sigill_handler; 101 sigill_action.sa_mask = sigmask; 102 103 sigset_t original_sigmask; 104 sigprocmask(SIG_SETMASK, &sigmask, &original_sigmask); 105 106 if (sigsetjmp(sigill_jmp, 1 /* save signals */) == 0) { 107 sigaction(SIGILL, &sigill_action, &sigill_original_action); 108 109 // This function cannot be inline asm because GCC will refuse to compile 110 // inline NEON instructions unless building with -mfpu=neon, which would 111 // defeat the point of probing for support at runtime. 112 CRYPTO_arm_neon_probe(); 113 supported = 1; 114 } 115 // Note that Android up to and including Lollipop doesn't restore the signal 116 // mask correctly after returning from a sigsetjmp. So that would need to be 117 // set again here if more probes were added. 118 // See https://android-review.googlesource.com/#/c/127624/ 119 120 sigaction(SIGILL, &sigill_original_action, NULL); 121 sigprocmask(SIG_SETMASK, &original_sigmask, NULL); 122 123 return supported; 124 } 125 126 #else 127 128 static int probe_for_NEON(void) { 129 return 0; 130 } 131 132 #endif /* !OPENSSL_NO_ASM && OPENSSL_ARM */ 133 134 void OPENSSL_cpuid_setup(void) { 135 if (getauxval == NULL) { 136 // On ARM, but not AArch64, try a NEON instruction and see whether it works 137 // in order to probe for NEON support. 138 // 139 // Note that |CRYPTO_is_NEON_capable| can be true even if 140 // |CRYPTO_set_NEON_capable| has never been called if the code was compiled 141 // with NEON support enabled (e.g. -mfpu=neon). 142 if (!g_set_neon_called && !CRYPTO_is_NEON_capable() && probe_for_NEON()) { 143 OPENSSL_armcap_P |= ARMV7_NEON; 144 } 145 return; 146 } 147 148 static const unsigned long AT_HWCAP = 16; 149 unsigned long hwcap = getauxval(AT_HWCAP); 150 151 #if defined(OPENSSL_ARM) 152 static const unsigned long kNEON = 1 << 12; 153 if ((hwcap & kNEON) == 0) { 154 return; 155 } 156 157 /* In 32-bit mode, the ARMv8 feature bits are in a different aux vector 158 * value. */ 159 static const unsigned long AT_HWCAP2 = 26; 160 hwcap = getauxval(AT_HWCAP2); 161 162 /* See /usr/include/asm/hwcap.h on an ARM installation for the source of 163 * these values. */ 164 static const unsigned long kAES = 1 << 0; 165 static const unsigned long kPMULL = 1 << 1; 166 static const unsigned long kSHA1 = 1 << 2; 167 static const unsigned long kSHA256 = 1 << 3; 168 #elif defined(OPENSSL_AARCH64) 169 /* See /usr/include/asm/hwcap.h on an aarch64 installation for the source of 170 * these values. */ 171 static const unsigned long kNEON = 1 << 1; 172 static const unsigned long kAES = 1 << 3; 173 static const unsigned long kPMULL = 1 << 4; 174 static const unsigned long kSHA1 = 1 << 5; 175 static const unsigned long kSHA256 = 1 << 6; 176 177 if ((hwcap & kNEON) == 0) { 178 return; 179 } 180 #endif 181 182 OPENSSL_armcap_P |= ARMV7_NEON; 183 184 if (hwcap & kAES) { 185 OPENSSL_armcap_P |= ARMV8_AES; 186 } 187 if (hwcap & kPMULL) { 188 OPENSSL_armcap_P |= ARMV8_PMULL; 189 } 190 if (hwcap & kSHA1) { 191 OPENSSL_armcap_P |= ARMV8_SHA1; 192 } 193 if (hwcap & kSHA256) { 194 OPENSSL_armcap_P |= ARMV8_SHA256; 195 } 196 } 197 198 #endif /* (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) && 199 !defined(OPENSSL_STATIC_ARMCAP) */ 200