| lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright 2011-2021 The OpenSSL Project Authors. All Rights Reserved. | 
|  | 3 | * | 
|  | 4 | * Licensed under the OpenSSL license (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 <setjmp.h> | 
|  | 14 | #include <signal.h> | 
|  | 15 | #include <openssl/crypto.h> | 
|  | 16 | #include "internal/cryptlib.h" | 
|  | 17 |  | 
|  | 18 | #include "arm_arch.h" | 
|  | 19 |  | 
|  | 20 | unsigned int OPENSSL_armcap_P = 0; | 
|  | 21 |  | 
|  | 22 | #if __ARM_MAX_ARCH__<7 | 
|  | 23 | void OPENSSL_cpuid_setup(void) | 
|  | 24 | { | 
|  | 25 | } | 
|  | 26 |  | 
|  | 27 | uint32_t OPENSSL_rdtsc(void) | 
|  | 28 | { | 
|  | 29 | return 0; | 
|  | 30 | } | 
|  | 31 | #else | 
|  | 32 | static sigset_t all_masked; | 
|  | 33 |  | 
|  | 34 | static sigjmp_buf ill_jmp; | 
|  | 35 | static void ill_handler(int sig) | 
|  | 36 | { | 
|  | 37 | siglongjmp(ill_jmp, sig); | 
|  | 38 | } | 
|  | 39 |  | 
|  | 40 | /* | 
|  | 41 | * Following subroutines could have been inlined, but it's not all | 
|  | 42 | * ARM compilers support inline assembler... | 
|  | 43 | */ | 
|  | 44 | void _armv7_neon_probe(void); | 
|  | 45 | void _armv8_aes_probe(void); | 
|  | 46 | void _armv8_sha1_probe(void); | 
|  | 47 | void _armv8_sha256_probe(void); | 
|  | 48 | void _armv8_pmull_probe(void); | 
|  | 49 | # ifdef __aarch64__ | 
|  | 50 | void _armv8_sha512_probe(void); | 
|  | 51 | # endif | 
|  | 52 | uint32_t _armv7_tick(void); | 
|  | 53 |  | 
|  | 54 | uint32_t OPENSSL_rdtsc(void) | 
|  | 55 | { | 
|  | 56 | if (OPENSSL_armcap_P & ARMV7_TICK) | 
|  | 57 | return _armv7_tick(); | 
|  | 58 | else | 
|  | 59 | return 0; | 
|  | 60 | } | 
|  | 61 |  | 
|  | 62 | # if defined(__GNUC__) && __GNUC__>=2 | 
|  | 63 | void OPENSSL_cpuid_setup(void) __attribute__ ((constructor)); | 
|  | 64 | # endif | 
|  | 65 |  | 
|  | 66 | # if defined(__GLIBC__) && defined(__GLIBC_PREREQ) | 
|  | 67 | #  if __GLIBC_PREREQ(2, 16) | 
|  | 68 | #   include <sys/auxv.h> | 
|  | 69 | #   define OSSL_IMPLEMENT_GETAUXVAL | 
|  | 70 | #  endif | 
|  | 71 | # elif defined(__ANDROID_API__) | 
|  | 72 | /* see https://developer.android.google.cn/ndk/guides/cpu-features */ | 
|  | 73 | #  if __ANDROID_API__ >= 18 | 
|  | 74 | #   include <sys/auxv.h> | 
|  | 75 | #   define OSSL_IMPLEMENT_GETAUXVAL | 
|  | 76 | #  endif | 
|  | 77 | # endif | 
|  | 78 | # if defined(__FreeBSD__) | 
|  | 79 | #  include <sys/param.h> | 
|  | 80 | #  if __FreeBSD_version >= 1200000 | 
|  | 81 | #   include <sys/auxv.h> | 
|  | 82 | #   define OSSL_IMPLEMENT_GETAUXVAL | 
|  | 83 |  | 
|  | 84 | static unsigned long getauxval(unsigned long key) | 
|  | 85 | { | 
|  | 86 | unsigned long val = 0ul; | 
|  | 87 |  | 
|  | 88 | if (elf_aux_info((int)key, &val, sizeof(val)) != 0) | 
|  | 89 | return 0ul; | 
|  | 90 |  | 
|  | 91 | return val; | 
|  | 92 | } | 
|  | 93 | #  endif | 
|  | 94 | # endif | 
|  | 95 |  | 
|  | 96 | /* | 
|  | 97 | * Android: according to https://developer.android.com/ndk/guides/cpu-features, | 
|  | 98 | * getauxval is supported starting with API level 18 | 
|  | 99 | */ | 
|  | 100 | #  if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 18 | 
|  | 101 | #   include <sys/auxv.h> | 
|  | 102 | #   define OSSL_IMPLEMENT_GETAUXVAL | 
|  | 103 | #  endif | 
|  | 104 |  | 
|  | 105 | /* | 
|  | 106 | * ARM puts the feature bits for Crypto Extensions in AT_HWCAP2, whereas | 
|  | 107 | * AArch64 used AT_HWCAP. | 
|  | 108 | */ | 
|  | 109 | # ifndef AT_HWCAP | 
|  | 110 | #  define AT_HWCAP               16 | 
|  | 111 | # endif | 
|  | 112 | # ifndef AT_HWCAP2 | 
|  | 113 | #  define AT_HWCAP2              26 | 
|  | 114 | # endif | 
|  | 115 | # if defined(__arm__) || defined (__arm) | 
|  | 116 | #  define HWCAP                  AT_HWCAP | 
|  | 117 | #  define HWCAP_NEON             (1 << 12) | 
|  | 118 |  | 
|  | 119 | #  define HWCAP_CE               AT_HWCAP2 | 
|  | 120 | #  define HWCAP_CE_AES           (1 << 0) | 
|  | 121 | #  define HWCAP_CE_PMULL         (1 << 1) | 
|  | 122 | #  define HWCAP_CE_SHA1          (1 << 2) | 
|  | 123 | #  define HWCAP_CE_SHA256        (1 << 3) | 
|  | 124 | # elif defined(__aarch64__) | 
|  | 125 | #  define HWCAP                  AT_HWCAP | 
|  | 126 | #  define HWCAP_NEON             (1 << 1) | 
|  | 127 |  | 
|  | 128 | #  define HWCAP_CE               HWCAP | 
|  | 129 | #  define HWCAP_CE_AES           (1 << 3) | 
|  | 130 | #  define HWCAP_CE_PMULL         (1 << 4) | 
|  | 131 | #  define HWCAP_CE_SHA1          (1 << 5) | 
|  | 132 | #  define HWCAP_CE_SHA256        (1 << 6) | 
|  | 133 | #  define HWCAP_CE_SHA512        (1 << 21) | 
|  | 134 | # endif | 
|  | 135 |  | 
|  | 136 | void OPENSSL_cpuid_setup(void) | 
|  | 137 | { | 
|  | 138 | const char *e; | 
|  | 139 | struct sigaction ill_oact, ill_act; | 
|  | 140 | sigset_t oset; | 
|  | 141 | static int trigger = 0; | 
|  | 142 |  | 
|  | 143 | if (trigger) | 
|  | 144 | return; | 
|  | 145 | trigger = 1; | 
|  | 146 |  | 
|  | 147 | if ((e = getenv("OPENSSL_armcap"))) { | 
|  | 148 | OPENSSL_armcap_P = (unsigned int)strtoul(e, NULL, 0); | 
|  | 149 | return; | 
|  | 150 | } | 
|  | 151 |  | 
|  | 152 | # if defined(__APPLE__) && !defined(__aarch64__) | 
|  | 153 | /* | 
|  | 154 | * Capability probing by catching SIGILL appears to be problematic | 
|  | 155 | * on iOS. But since Apple universe is "monocultural", it's actually | 
|  | 156 | * possible to simply set pre-defined processor capability mask. | 
|  | 157 | */ | 
|  | 158 | if (1) { | 
|  | 159 | OPENSSL_armcap_P = ARMV7_NEON; | 
|  | 160 | return; | 
|  | 161 | } | 
|  | 162 | /* | 
|  | 163 | * One could do same even for __aarch64__ iOS builds. It's not done | 
|  | 164 | * exclusively for reasons of keeping code unified across platforms. | 
|  | 165 | * Unified code works because it never triggers SIGILL on Apple | 
|  | 166 | * devices... | 
|  | 167 | */ | 
|  | 168 | # endif | 
|  | 169 |  | 
|  | 170 | OPENSSL_armcap_P = 0; | 
|  | 171 |  | 
|  | 172 | # ifdef OSSL_IMPLEMENT_GETAUXVAL | 
|  | 173 | if (getauxval(HWCAP) & HWCAP_NEON) { | 
|  | 174 | unsigned long hwcap = getauxval(HWCAP_CE); | 
|  | 175 |  | 
|  | 176 | OPENSSL_armcap_P |= ARMV7_NEON; | 
|  | 177 |  | 
|  | 178 | if (hwcap & HWCAP_CE_AES) | 
|  | 179 | OPENSSL_armcap_P |= ARMV8_AES; | 
|  | 180 |  | 
|  | 181 | if (hwcap & HWCAP_CE_PMULL) | 
|  | 182 | OPENSSL_armcap_P |= ARMV8_PMULL; | 
|  | 183 |  | 
|  | 184 | if (hwcap & HWCAP_CE_SHA1) | 
|  | 185 | OPENSSL_armcap_P |= ARMV8_SHA1; | 
|  | 186 |  | 
|  | 187 | if (hwcap & HWCAP_CE_SHA256) | 
|  | 188 | OPENSSL_armcap_P |= ARMV8_SHA256; | 
|  | 189 |  | 
|  | 190 | #  ifdef __aarch64__ | 
|  | 191 | if (hwcap & HWCAP_CE_SHA512) | 
|  | 192 | OPENSSL_armcap_P |= ARMV8_SHA512; | 
|  | 193 | #  endif | 
|  | 194 | } | 
|  | 195 | # endif | 
|  | 196 |  | 
|  | 197 | sigfillset(&all_masked); | 
|  | 198 | sigdelset(&all_masked, SIGILL); | 
|  | 199 | sigdelset(&all_masked, SIGTRAP); | 
|  | 200 | sigdelset(&all_masked, SIGFPE); | 
|  | 201 | sigdelset(&all_masked, SIGBUS); | 
|  | 202 | sigdelset(&all_masked, SIGSEGV); | 
|  | 203 |  | 
|  | 204 | memset(&ill_act, 0, sizeof(ill_act)); | 
|  | 205 | ill_act.sa_handler = ill_handler; | 
|  | 206 | ill_act.sa_mask = all_masked; | 
|  | 207 |  | 
|  | 208 | sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset); | 
|  | 209 | sigaction(SIGILL, &ill_act, &ill_oact); | 
|  | 210 |  | 
|  | 211 | /* If we used getauxval, we already have all the values */ | 
|  | 212 | # ifndef OSSL_IMPLEMENT_GETAUXVAL | 
|  | 213 | if (sigsetjmp(ill_jmp, 1) == 0) { | 
|  | 214 | _armv7_neon_probe(); | 
|  | 215 | OPENSSL_armcap_P |= ARMV7_NEON; | 
|  | 216 | if (sigsetjmp(ill_jmp, 1) == 0) { | 
|  | 217 | _armv8_pmull_probe(); | 
|  | 218 | OPENSSL_armcap_P |= ARMV8_PMULL | ARMV8_AES; | 
|  | 219 | } else if (sigsetjmp(ill_jmp, 1) == 0) { | 
|  | 220 | _armv8_aes_probe(); | 
|  | 221 | OPENSSL_armcap_P |= ARMV8_AES; | 
|  | 222 | } | 
|  | 223 | if (sigsetjmp(ill_jmp, 1) == 0) { | 
|  | 224 | _armv8_sha1_probe(); | 
|  | 225 | OPENSSL_armcap_P |= ARMV8_SHA1; | 
|  | 226 | } | 
|  | 227 | if (sigsetjmp(ill_jmp, 1) == 0) { | 
|  | 228 | _armv8_sha256_probe(); | 
|  | 229 | OPENSSL_armcap_P |= ARMV8_SHA256; | 
|  | 230 | } | 
|  | 231 | #  if defined(__aarch64__) && !defined(__APPLE__) | 
|  | 232 | if (sigsetjmp(ill_jmp, 1) == 0) { | 
|  | 233 | _armv8_sha512_probe(); | 
|  | 234 | OPENSSL_armcap_P |= ARMV8_SHA512; | 
|  | 235 | } | 
|  | 236 | #  endif | 
|  | 237 | } | 
|  | 238 | # endif | 
|  | 239 |  | 
|  | 240 | /* Things that getauxval didn't tell us */ | 
|  | 241 | if (sigsetjmp(ill_jmp, 1) == 0) { | 
|  | 242 | _armv7_tick(); | 
|  | 243 | OPENSSL_armcap_P |= ARMV7_TICK; | 
|  | 244 | } | 
|  | 245 |  | 
|  | 246 | sigaction(SIGILL, &ill_oact, NULL); | 
|  | 247 | sigprocmask(SIG_SETMASK, &oset, NULL); | 
|  | 248 | } | 
|  | 249 | #endif |