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