1238384Sjkim#include <stdio.h> 2238384Sjkim#include <stdlib.h> 3238384Sjkim#include <string.h> 4238384Sjkim#include <setjmp.h> 5238384Sjkim#include <signal.h> 6238384Sjkim#include <sys/time.h> 7238384Sjkim#include <openssl/bn.h> 8238384Sjkim 9238384Sjkim#define SPARCV9_TICK_PRIVILEGED (1<<0) 10238384Sjkim#define SPARCV9_PREFER_FPU (1<<1) 11238384Sjkim#define SPARCV9_VIS1 (1<<2) 12238384Sjkim#define SPARCV9_VIS2 (1<<3) /* reserved */ 13238384Sjkim#define SPARCV9_FMADD (1<<4) /* reserved for SPARC64 V */ 14238384Sjkim 15238384Sjkimstatic int OPENSSL_sparcv9cap_P=SPARCV9_TICK_PRIVILEGED; 16238384Sjkim 17238384Sjkimint bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np,const BN_ULONG *n0, int num) 18238384Sjkim { 19238384Sjkim int bn_mul_mont_fpu(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np,const BN_ULONG *n0, int num); 20238384Sjkim int bn_mul_mont_int(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np,const BN_ULONG *n0, int num); 21238384Sjkim 22238384Sjkim if (num>=8 && !(num&1) && 23238384Sjkim (OPENSSL_sparcv9cap_P&(SPARCV9_PREFER_FPU|SPARCV9_VIS1)) == 24238384Sjkim (SPARCV9_PREFER_FPU|SPARCV9_VIS1)) 25238384Sjkim return bn_mul_mont_fpu(rp,ap,bp,np,n0,num); 26238384Sjkim else 27238384Sjkim return bn_mul_mont_int(rp,ap,bp,np,n0,num); 28238384Sjkim } 29238384Sjkim 30238384Sjkimunsigned long _sparcv9_rdtick(void); 31238384Sjkimvoid _sparcv9_vis1_probe(void); 32238384Sjkimunsigned long _sparcv9_vis1_instrument(void); 33238384Sjkimvoid _sparcv9_vis2_probe(void); 34238384Sjkimvoid _sparcv9_fmadd_probe(void); 35238384Sjkim 36238384Sjkimunsigned long OPENSSL_rdtsc(void) 37238384Sjkim { 38238384Sjkim if (OPENSSL_sparcv9cap_P&SPARCV9_TICK_PRIVILEGED) 39238384Sjkim#if defined(__sun) && defined(__SVR4) 40238384Sjkim return gethrtime(); 41238384Sjkim#else 42238384Sjkim return 0; 43238384Sjkim#endif 44238384Sjkim else 45238384Sjkim return _sparcv9_rdtick(); 46238384Sjkim } 47238384Sjkim 48238384Sjkim#if 0 && defined(__sun) && defined(__SVR4) 49238384Sjkim/* This code path is disabled, because of incompatibility of 50238384Sjkim * libdevinfo.so.1 and libmalloc.so.1 (see below for details) 51238384Sjkim */ 52238384Sjkim#include <malloc.h> 53238384Sjkim#include <dlfcn.h> 54238384Sjkim#include <libdevinfo.h> 55238384Sjkim#include <sys/systeminfo.h> 56238384Sjkim 57238384Sjkimtypedef di_node_t (*di_init_t)(const char *,uint_t); 58238384Sjkimtypedef void (*di_fini_t)(di_node_t); 59238384Sjkimtypedef char * (*di_node_name_t)(di_node_t); 60238384Sjkimtypedef int (*di_walk_node_t)(di_node_t,uint_t,di_node_name_t,int (*)(di_node_t,di_node_name_t)); 61238384Sjkim 62238384Sjkim#define DLLINK(h,name) (name=(name##_t)dlsym((h),#name)) 63238384Sjkim 64238384Sjkimstatic int walk_nodename(di_node_t node, di_node_name_t di_node_name) 65238384Sjkim { 66238384Sjkim char *name = (*di_node_name)(node); 67238384Sjkim 68238384Sjkim /* This is expected to catch all UltraSPARC flavors prior T1 */ 69238384Sjkim if (!strcmp (name,"SUNW,UltraSPARC") || 70238384Sjkim !strncmp(name,"SUNW,UltraSPARC-I",17)) /* covers II,III,IV */ 71238384Sjkim { 72238384Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU|SPARCV9_VIS1; 73238384Sjkim 74238384Sjkim /* %tick is privileged only on UltraSPARC-I/II, but not IIe */ 75238384Sjkim if (name[14]!='\0' && name[17]!='\0' && name[18]!='\0') 76238384Sjkim OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; 77238384Sjkim 78238384Sjkim return DI_WALK_TERMINATE; 79238384Sjkim } 80238384Sjkim /* This is expected to catch remaining UltraSPARCs, such as T1 */ 81238384Sjkim else if (!strncmp(name,"SUNW,UltraSPARC",15)) 82238384Sjkim { 83238384Sjkim OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; 84238384Sjkim 85238384Sjkim return DI_WALK_TERMINATE; 86238384Sjkim } 87238384Sjkim 88238384Sjkim return DI_WALK_CONTINUE; 89238384Sjkim } 90238384Sjkim 91238384Sjkimvoid OPENSSL_cpuid_setup(void) 92238384Sjkim { 93238384Sjkim void *h; 94238384Sjkim char *e,si[256]; 95238384Sjkim static int trigger=0; 96238384Sjkim 97238384Sjkim if (trigger) return; 98238384Sjkim trigger=1; 99238384Sjkim 100238384Sjkim if ((e=getenv("OPENSSL_sparcv9cap"))) 101238384Sjkim { 102238384Sjkim OPENSSL_sparcv9cap_P=strtoul(e,NULL,0); 103238384Sjkim return; 104238384Sjkim } 105238384Sjkim 106238384Sjkim if (sysinfo(SI_MACHINE,si,sizeof(si))>0) 107238384Sjkim { 108238384Sjkim if (strcmp(si,"sun4v")) 109238384Sjkim /* FPU is preferred for all CPUs, but US-T1/2 */ 110238384Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU; 111238384Sjkim } 112238384Sjkim 113238384Sjkim if (sysinfo(SI_ISALIST,si,sizeof(si))>0) 114238384Sjkim { 115238384Sjkim if (strstr(si,"+vis")) 116238384Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_VIS1; 117238384Sjkim if (strstr(si,"+vis2")) 118238384Sjkim { 119238384Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_VIS2; 120238384Sjkim OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; 121238384Sjkim return; 122238384Sjkim } 123238384Sjkim } 124238384Sjkim#ifdef M_KEEP 125238384Sjkim /* 126238384Sjkim * Solaris libdevinfo.so.1 is effectively incomatible with 127238384Sjkim * libmalloc.so.1. Specifically, if application is linked with 128238384Sjkim * -lmalloc, it crashes upon startup with SIGSEGV in 129238384Sjkim * free(3LIBMALLOC) called by di_fini. Prior call to 130238384Sjkim * mallopt(M_KEEP,0) somehow helps... But not always... 131238384Sjkim */ 132238384Sjkim if ((h = dlopen(NULL,RTLD_LAZY))) 133238384Sjkim { 134238384Sjkim union { void *p; int (*f)(int,int); } sym; 135238384Sjkim if ((sym.p = dlsym(h,"mallopt"))) (*sym.f)(M_KEEP,0); 136238384Sjkim dlclose(h); 137238384Sjkim } 138238384Sjkim#endif 139238384Sjkim if ((h = dlopen("libdevinfo.so.1",RTLD_LAZY))) do 140238384Sjkim { 141238384Sjkim di_init_t di_init; 142238384Sjkim di_fini_t di_fini; 143238384Sjkim di_walk_node_t di_walk_node; 144238384Sjkim di_node_name_t di_node_name; 145238384Sjkim di_node_t root_node; 146238384Sjkim 147238384Sjkim if (!DLLINK(h,di_init)) break; 148238384Sjkim if (!DLLINK(h,di_fini)) break; 149238384Sjkim if (!DLLINK(h,di_walk_node)) break; 150238384Sjkim if (!DLLINK(h,di_node_name)) break; 151238384Sjkim 152238384Sjkim if ((root_node = (*di_init)("/",DINFOSUBTREE))!=DI_NODE_NIL) 153238384Sjkim { 154238384Sjkim (*di_walk_node)(root_node,DI_WALK_SIBFIRST, 155238384Sjkim di_node_name,walk_nodename); 156238384Sjkim (*di_fini)(root_node); 157238384Sjkim } 158238384Sjkim } while(0); 159238384Sjkim 160238384Sjkim if (h) dlclose(h); 161238384Sjkim } 162238384Sjkim 163238384Sjkim#else 164238384Sjkim 165238384Sjkimstatic sigjmp_buf common_jmp; 166238384Sjkimstatic void common_handler(int sig) { siglongjmp(common_jmp,sig); } 167238384Sjkim 168238384Sjkimvoid OPENSSL_cpuid_setup(void) 169238384Sjkim { 170238384Sjkim char *e; 171238384Sjkim struct sigaction common_act,ill_oact,bus_oact; 172238384Sjkim sigset_t all_masked,oset; 173238384Sjkim static int trigger=0; 174238384Sjkim 175238384Sjkim if (trigger) return; 176238384Sjkim trigger=1; 177238384Sjkim 178238384Sjkim if ((e=getenv("OPENSSL_sparcv9cap"))) 179238384Sjkim { 180238384Sjkim OPENSSL_sparcv9cap_P=strtoul(e,NULL,0); 181238384Sjkim return; 182238384Sjkim } 183238384Sjkim 184238384Sjkim /* Initial value, fits UltraSPARC-I&II... */ 185238384Sjkim OPENSSL_sparcv9cap_P = SPARCV9_PREFER_FPU|SPARCV9_TICK_PRIVILEGED; 186238384Sjkim 187238384Sjkim sigfillset(&all_masked); 188238384Sjkim sigdelset(&all_masked,SIGILL); 189238384Sjkim sigdelset(&all_masked,SIGTRAP); 190238384Sjkim#ifdef SIGEMT 191238384Sjkim sigdelset(&all_masked,SIGEMT); 192238384Sjkim#endif 193238384Sjkim sigdelset(&all_masked,SIGFPE); 194238384Sjkim sigdelset(&all_masked,SIGBUS); 195238384Sjkim sigdelset(&all_masked,SIGSEGV); 196238384Sjkim sigprocmask(SIG_SETMASK,&all_masked,&oset); 197238384Sjkim 198238384Sjkim memset(&common_act,0,sizeof(common_act)); 199238384Sjkim common_act.sa_handler = common_handler; 200238384Sjkim common_act.sa_mask = all_masked; 201238384Sjkim 202238384Sjkim sigaction(SIGILL,&common_act,&ill_oact); 203238384Sjkim sigaction(SIGBUS,&common_act,&bus_oact);/* T1 fails 16-bit ldda [on Linux] */ 204238384Sjkim 205238384Sjkim if (sigsetjmp(common_jmp,1) == 0) 206238384Sjkim { 207238384Sjkim _sparcv9_rdtick(); 208238384Sjkim OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; 209238384Sjkim } 210238384Sjkim 211238384Sjkim if (sigsetjmp(common_jmp,1) == 0) 212238384Sjkim { 213238384Sjkim _sparcv9_vis1_probe(); 214238384Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_VIS1; 215238384Sjkim /* detect UltraSPARC-Tx, see sparccpud.S for details... */ 216238384Sjkim if (_sparcv9_vis1_instrument() >= 12) 217238384Sjkim OPENSSL_sparcv9cap_P &= ~(SPARCV9_VIS1|SPARCV9_PREFER_FPU); 218238384Sjkim else 219238384Sjkim { 220238384Sjkim _sparcv9_vis2_probe(); 221238384Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_VIS2; 222238384Sjkim } 223238384Sjkim } 224238384Sjkim 225238384Sjkim if (sigsetjmp(common_jmp,1) == 0) 226238384Sjkim { 227238384Sjkim _sparcv9_fmadd_probe(); 228238384Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_FMADD; 229238384Sjkim } 230238384Sjkim 231238384Sjkim sigaction(SIGBUS,&bus_oact,NULL); 232238384Sjkim sigaction(SIGILL,&ill_oact,NULL); 233238384Sjkim 234238384Sjkim sigprocmask(SIG_SETMASK,&oset,NULL); 235238384Sjkim } 236238384Sjkim 237238384Sjkim#endif 238