sparcv9cap.c revision 296341
1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <setjmp.h> 5#include <signal.h> 6#include <sys/time.h> 7#include <openssl/bn.h> 8 9#define SPARCV9_TICK_PRIVILEGED (1<<0) 10#define SPARCV9_PREFER_FPU (1<<1) 11#define SPARCV9_VIS1 (1<<2) 12#define SPARCV9_VIS2 (1<<3) /* reserved */ 13#define SPARCV9_FMADD (1<<4) /* reserved for SPARC64 V */ 14 15static int OPENSSL_sparcv9cap_P = SPARCV9_TICK_PRIVILEGED; 16 17int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, 18 const BN_ULONG *np, const BN_ULONG *n0, int num) 19{ 20 int bn_mul_mont_fpu(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, 21 const BN_ULONG *np, const BN_ULONG *n0, int num); 22 int bn_mul_mont_int(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, 23 const BN_ULONG *np, const BN_ULONG *n0, int num); 24 25 if (num >= 8 && !(num & 1) && 26 (OPENSSL_sparcv9cap_P & (SPARCV9_PREFER_FPU | SPARCV9_VIS1)) == 27 (SPARCV9_PREFER_FPU | SPARCV9_VIS1)) 28 return bn_mul_mont_fpu(rp, ap, bp, np, n0, num); 29 else 30 return bn_mul_mont_int(rp, ap, bp, np, n0, num); 31} 32 33unsigned long _sparcv9_rdtick(void); 34void _sparcv9_vis1_probe(void); 35unsigned long _sparcv9_vis1_instrument(void); 36void _sparcv9_vis2_probe(void); 37void _sparcv9_fmadd_probe(void); 38 39unsigned long OPENSSL_rdtsc(void) 40{ 41 if (OPENSSL_sparcv9cap_P & SPARCV9_TICK_PRIVILEGED) 42#if defined(__sun) && defined(__SVR4) 43 return gethrtime(); 44#else 45 return 0; 46#endif 47 else 48 return _sparcv9_rdtick(); 49} 50 51#if 0 && defined(__sun) && defined(__SVR4) 52/* 53 * This code path is disabled, because of incompatibility of libdevinfo.so.1 54 * and libmalloc.so.1 (see below for details) 55 */ 56# include <malloc.h> 57# include <dlfcn.h> 58# include <libdevinfo.h> 59# include <sys/systeminfo.h> 60 61typedef di_node_t(*di_init_t) (const char *, uint_t); 62typedef void (*di_fini_t) (di_node_t); 63typedef char *(*di_node_name_t) (di_node_t); 64typedef int (*di_walk_node_t) (di_node_t, uint_t, di_node_name_t, 65 int (*)(di_node_t, di_node_name_t)); 66 67# define DLLINK(h,name) (name=(name##_t)dlsym((h),#name)) 68 69static int walk_nodename(di_node_t node, di_node_name_t di_node_name) 70{ 71 char *name = (*di_node_name) (node); 72 73 /* This is expected to catch all UltraSPARC flavors prior T1 */ 74 if (!strcmp(name, "SUNW,UltraSPARC") || 75 /* covers II,III,IV */ 76 !strncmp(name, "SUNW,UltraSPARC-I", 17)) { 77 OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU | SPARCV9_VIS1; 78 79 /* %tick is privileged only on UltraSPARC-I/II, but not IIe */ 80 if (name[14] != '\0' && name[17] != '\0' && name[18] != '\0') 81 OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; 82 83 return DI_WALK_TERMINATE; 84 } 85 /* This is expected to catch remaining UltraSPARCs, such as T1 */ 86 else if (!strncmp(name, "SUNW,UltraSPARC", 15)) { 87 OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; 88 89 return DI_WALK_TERMINATE; 90 } 91 92 return DI_WALK_CONTINUE; 93} 94 95void OPENSSL_cpuid_setup(void) 96{ 97 void *h; 98 char *e, si[256]; 99 static int trigger = 0; 100 101 if (trigger) 102 return; 103 trigger = 1; 104 105 if ((e = getenv("OPENSSL_sparcv9cap"))) { 106 OPENSSL_sparcv9cap_P = strtoul(e, NULL, 0); 107 return; 108 } 109 110 if (sysinfo(SI_MACHINE, si, sizeof(si)) > 0) { 111 if (strcmp(si, "sun4v")) 112 /* FPU is preferred for all CPUs, but US-T1/2 */ 113 OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU; 114 } 115 116 if (sysinfo(SI_ISALIST, si, sizeof(si)) > 0) { 117 if (strstr(si, "+vis")) 118 OPENSSL_sparcv9cap_P |= SPARCV9_VIS1; 119 if (strstr(si, "+vis2")) { 120 OPENSSL_sparcv9cap_P |= SPARCV9_VIS2; 121 OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; 122 return; 123 } 124 } 125# ifdef M_KEEP 126 /* 127 * Solaris libdevinfo.so.1 is effectively incomatible with 128 * libmalloc.so.1. Specifically, if application is linked with 129 * -lmalloc, it crashes upon startup with SIGSEGV in 130 * free(3LIBMALLOC) called by di_fini. Prior call to 131 * mallopt(M_KEEP,0) somehow helps... But not always... 132 */ 133 if ((h = dlopen(NULL, RTLD_LAZY))) { 134 union { 135 void *p; 136 int (*f) (int, int); 137 } sym; 138 if ((sym.p = dlsym(h, "mallopt"))) 139 (*sym.f) (M_KEEP, 0); 140 dlclose(h); 141 } 142# endif 143 if ((h = dlopen("libdevinfo.so.1", RTLD_LAZY))) 144 do { 145 di_init_t di_init; 146 di_fini_t di_fini; 147 di_walk_node_t di_walk_node; 148 di_node_name_t di_node_name; 149 di_node_t root_node; 150 151 if (!DLLINK(h, di_init)) 152 break; 153 if (!DLLINK(h, di_fini)) 154 break; 155 if (!DLLINK(h, di_walk_node)) 156 break; 157 if (!DLLINK(h, di_node_name)) 158 break; 159 160 if ((root_node = (*di_init) ("/", DINFOSUBTREE)) != DI_NODE_NIL) { 161 (*di_walk_node) (root_node, DI_WALK_SIBFIRST, 162 di_node_name, walk_nodename); 163 (*di_fini) (root_node); 164 } 165 } while (0); 166 167 if (h) 168 dlclose(h); 169} 170 171#else 172 173static sigjmp_buf common_jmp; 174static void common_handler(int sig) 175{ 176 siglongjmp(common_jmp, sig); 177} 178 179void OPENSSL_cpuid_setup(void) 180{ 181 char *e; 182 struct sigaction common_act, ill_oact, bus_oact; 183 sigset_t all_masked, oset; 184 static int trigger = 0; 185 186 if (trigger) 187 return; 188 trigger = 1; 189 190 if ((e = getenv("OPENSSL_sparcv9cap"))) { 191 OPENSSL_sparcv9cap_P = strtoul(e, NULL, 0); 192 return; 193 } 194 195 /* Initial value, fits UltraSPARC-I&II... */ 196 OPENSSL_sparcv9cap_P = SPARCV9_PREFER_FPU | SPARCV9_TICK_PRIVILEGED; 197 198 sigfillset(&all_masked); 199 sigdelset(&all_masked, SIGILL); 200 sigdelset(&all_masked, SIGTRAP); 201# ifdef SIGEMT 202 sigdelset(&all_masked, SIGEMT); 203# endif 204 sigdelset(&all_masked, SIGFPE); 205 sigdelset(&all_masked, SIGBUS); 206 sigdelset(&all_masked, SIGSEGV); 207 sigprocmask(SIG_SETMASK, &all_masked, &oset); 208 209 memset(&common_act, 0, sizeof(common_act)); 210 common_act.sa_handler = common_handler; 211 common_act.sa_mask = all_masked; 212 213 sigaction(SIGILL, &common_act, &ill_oact); 214 sigaction(SIGBUS, &common_act, &bus_oact); /* T1 fails 16-bit ldda [on 215 * Linux] */ 216 217 if (sigsetjmp(common_jmp, 1) == 0) { 218 _sparcv9_rdtick(); 219 OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; 220 } 221 222 if (sigsetjmp(common_jmp, 1) == 0) { 223 _sparcv9_vis1_probe(); 224 OPENSSL_sparcv9cap_P |= SPARCV9_VIS1; 225 /* detect UltraSPARC-Tx, see sparccpud.S for details... */ 226 if (_sparcv9_vis1_instrument() >= 12) 227 OPENSSL_sparcv9cap_P &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU); 228 else { 229 _sparcv9_vis2_probe(); 230 OPENSSL_sparcv9cap_P |= SPARCV9_VIS2; 231 } 232 } 233 234 if (sigsetjmp(common_jmp, 1) == 0) { 235 _sparcv9_fmadd_probe(); 236 OPENSSL_sparcv9cap_P |= SPARCV9_FMADD; 237 } 238 239 sigaction(SIGBUS, &bus_oact, NULL); 240 sigaction(SIGILL, &ill_oact, NULL); 241 242 sigprocmask(SIG_SETMASK, &oset, NULL); 243} 244 245#endif 246