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