armcap.c revision 325334
1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <setjmp.h> 5#include <signal.h> 6#include <crypto.h> 7 8#include "arm_arch.h" 9 10__attribute__ ((visibility("hidden"))) 11unsigned int OPENSSL_armcap_P = 0; 12 13#if __ARM_MAX_ARCH__<7 14void OPENSSL_cpuid_setup(void) 15{ 16} 17 18unsigned long OPENSSL_rdtsc(void) 19{ 20 return 0; 21} 22#else 23static sigset_t all_masked; 24 25static sigjmp_buf ill_jmp; 26static void ill_handler(int sig) 27{ 28 siglongjmp(ill_jmp, sig); 29} 30 31/* 32 * Following subroutines could have been inlined, but it's not all 33 * ARM compilers support inline assembler... 34 */ 35void _armv7_neon_probe(void); 36void _armv8_aes_probe(void); 37void _armv8_sha1_probe(void); 38void _armv8_sha256_probe(void); 39void _armv8_pmull_probe(void); 40unsigned long _armv7_tick(void); 41 42unsigned long OPENSSL_rdtsc(void) 43{ 44 if (OPENSSL_armcap_P & ARMV7_TICK) 45 return _armv7_tick(); 46 else 47 return 0; 48} 49 50/* 51 * Use a weak reference to getauxval() so we can use it if it is available but 52 * don't break the build if it is not. 53 */ 54# if defined(__GNUC__) && __GNUC__>=2 55void OPENSSL_cpuid_setup(void) __attribute__ ((constructor)); 56extern unsigned long getauxval(unsigned long type) __attribute__ ((weak)); 57# else 58static unsigned long (*getauxval) (unsigned long) = NULL; 59# endif 60 61/* 62 * ARM puts the the feature bits for Crypto Extensions in AT_HWCAP2, whereas 63 * AArch64 used AT_HWCAP. 64 */ 65# if defined(__arm__) || defined (__arm) 66# define HWCAP 16 67 /* AT_HWCAP */ 68# define HWCAP_NEON (1 << 12) 69 70# define HWCAP_CE 26 71 /* AT_HWCAP2 */ 72# define HWCAP_CE_AES (1 << 0) 73# define HWCAP_CE_PMULL (1 << 1) 74# define HWCAP_CE_SHA1 (1 << 2) 75# define HWCAP_CE_SHA256 (1 << 3) 76# elif defined(__aarch64__) 77# define HWCAP 16 78 /* AT_HWCAP */ 79# define HWCAP_NEON (1 << 1) 80 81# define HWCAP_CE HWCAP 82# define HWCAP_CE_AES (1 << 3) 83# define HWCAP_CE_PMULL (1 << 4) 84# define HWCAP_CE_SHA1 (1 << 5) 85# define HWCAP_CE_SHA256 (1 << 6) 86# endif 87 88void OPENSSL_cpuid_setup(void) 89{ 90 char *e; 91 struct sigaction ill_oact, ill_act; 92 sigset_t oset; 93 static int trigger = 0; 94 95 if (trigger) 96 return; 97 trigger = 1; 98 99 if ((e = getenv("OPENSSL_armcap"))) { 100 OPENSSL_armcap_P = (unsigned int)strtoul(e, NULL, 0); 101 return; 102 } 103 104 sigfillset(&all_masked); 105 sigdelset(&all_masked, SIGILL); 106 sigdelset(&all_masked, SIGTRAP); 107 sigdelset(&all_masked, SIGFPE); 108 sigdelset(&all_masked, SIGBUS); 109 sigdelset(&all_masked, SIGSEGV); 110 111 OPENSSL_armcap_P = 0; 112 113 memset(&ill_act, 0, sizeof(ill_act)); 114 ill_act.sa_handler = ill_handler; 115 ill_act.sa_mask = all_masked; 116 117 sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset); 118 sigaction(SIGILL, &ill_act, &ill_oact); 119 120 if (getauxval != NULL) { 121 if (getauxval(HWCAP) & HWCAP_NEON) { 122 unsigned long hwcap = getauxval(HWCAP_CE); 123 124 OPENSSL_armcap_P |= ARMV7_NEON; 125 126 if (hwcap & HWCAP_CE_AES) 127 OPENSSL_armcap_P |= ARMV8_AES; 128 129 if (hwcap & HWCAP_CE_PMULL) 130 OPENSSL_armcap_P |= ARMV8_PMULL; 131 132 if (hwcap & HWCAP_CE_SHA1) 133 OPENSSL_armcap_P |= ARMV8_SHA1; 134 135 if (hwcap & HWCAP_CE_SHA256) 136 OPENSSL_armcap_P |= ARMV8_SHA256; 137 } 138 } else if (sigsetjmp(ill_jmp, 1) == 0) { 139 _armv7_neon_probe(); 140 OPENSSL_armcap_P |= ARMV7_NEON; 141 if (sigsetjmp(ill_jmp, 1) == 0) { 142 _armv8_pmull_probe(); 143 OPENSSL_armcap_P |= ARMV8_PMULL | ARMV8_AES; 144 } else if (sigsetjmp(ill_jmp, 1) == 0) { 145 _armv8_aes_probe(); 146 OPENSSL_armcap_P |= ARMV8_AES; 147 } 148 if (sigsetjmp(ill_jmp, 1) == 0) { 149 _armv8_sha1_probe(); 150 OPENSSL_armcap_P |= ARMV8_SHA1; 151 } 152 if (sigsetjmp(ill_jmp, 1) == 0) { 153 _armv8_sha256_probe(); 154 OPENSSL_armcap_P |= ARMV8_SHA256; 155 } 156 } 157 if (sigsetjmp(ill_jmp, 1) == 0) { 158 _armv7_tick(); 159 OPENSSL_armcap_P |= ARMV7_TICK; 160 } 161 162 sigaction(SIGILL, &ill_oact, NULL); 163 sigprocmask(SIG_SETMASK, &oset, NULL); 164} 165#endif 166