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 9280304Sjkim#define SPARCV9_TICK_PRIVILEGED (1<<0) 10280304Sjkim#define SPARCV9_PREFER_FPU (1<<1) 11280304Sjkim#define SPARCV9_VIS1 (1<<2) 12280304Sjkim#define SPARCV9_VIS2 (1<<3) /* reserved */ 13280304Sjkim#define SPARCV9_FMADD (1<<4) /* reserved for SPARC64 V */ 14238384Sjkim 15280304Sjkimstatic int OPENSSL_sparcv9cap_P = SPARCV9_TICK_PRIVILEGED; 16238384Sjkim 17280304Sjkimint bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, 18280304Sjkim const BN_ULONG *np, const BN_ULONG *n0, int num) 19280304Sjkim{ 20280304Sjkim int bn_mul_mont_fpu(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, 21280304Sjkim const BN_ULONG *np, const BN_ULONG *n0, int num); 22280304Sjkim int bn_mul_mont_int(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, 23280304Sjkim const BN_ULONG *np, const BN_ULONG *n0, int num); 24238384Sjkim 25280304Sjkim if (num >= 8 && !(num & 1) && 26280304Sjkim (OPENSSL_sparcv9cap_P & (SPARCV9_PREFER_FPU | SPARCV9_VIS1)) == 27280304Sjkim (SPARCV9_PREFER_FPU | SPARCV9_VIS1)) 28280304Sjkim return bn_mul_mont_fpu(rp, ap, bp, np, n0, num); 29280304Sjkim else 30280304Sjkim return bn_mul_mont_int(rp, ap, bp, np, n0, num); 31280304Sjkim} 32238384Sjkim 33280304Sjkimunsigned long _sparcv9_rdtick(void); 34280304Sjkimvoid _sparcv9_vis1_probe(void); 35280304Sjkimunsigned long _sparcv9_vis1_instrument(void); 36280304Sjkimvoid _sparcv9_vis2_probe(void); 37280304Sjkimvoid _sparcv9_fmadd_probe(void); 38238384Sjkim 39238384Sjkimunsigned long OPENSSL_rdtsc(void) 40280304Sjkim{ 41280304Sjkim if (OPENSSL_sparcv9cap_P & SPARCV9_TICK_PRIVILEGED) 42238384Sjkim#if defined(__sun) && defined(__SVR4) 43280304Sjkim return gethrtime(); 44238384Sjkim#else 45280304Sjkim return 0; 46238384Sjkim#endif 47280304Sjkim else 48280304Sjkim return _sparcv9_rdtick(); 49280304Sjkim} 50238384Sjkim 51238384Sjkim#if 0 && defined(__sun) && defined(__SVR4) 52280304Sjkim/* 53280304Sjkim * This code path is disabled, because of incompatibility of libdevinfo.so.1 54280304Sjkim * and libmalloc.so.1 (see below for details) 55238384Sjkim */ 56280304Sjkim# include <malloc.h> 57280304Sjkim# include <dlfcn.h> 58280304Sjkim# include <libdevinfo.h> 59280304Sjkim# include <sys/systeminfo.h> 60238384Sjkim 61280304Sjkimtypedef di_node_t(*di_init_t) (const char *, uint_t); 62280304Sjkimtypedef void (*di_fini_t) (di_node_t); 63280304Sjkimtypedef char *(*di_node_name_t) (di_node_t); 64280304Sjkimtypedef int (*di_walk_node_t) (di_node_t, uint_t, di_node_name_t, 65280304Sjkim int (*)(di_node_t, di_node_name_t)); 66238384Sjkim 67280304Sjkim# define DLLINK(h,name) (name=(name##_t)dlsym((h),#name)) 68238384Sjkim 69238384Sjkimstatic int walk_nodename(di_node_t node, di_node_name_t di_node_name) 70280304Sjkim{ 71280304Sjkim char *name = (*di_node_name) (node); 72238384Sjkim 73280304Sjkim /* This is expected to catch all UltraSPARC flavors prior T1 */ 74280304Sjkim if (!strcmp(name, "SUNW,UltraSPARC") || 75280304Sjkim /* covers II,III,IV */ 76280304Sjkim !strncmp(name, "SUNW,UltraSPARC-I", 17)) { 77280304Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU | SPARCV9_VIS1; 78238384Sjkim 79280304Sjkim /* %tick is privileged only on UltraSPARC-I/II, but not IIe */ 80280304Sjkim if (name[14] != '\0' && name[17] != '\0' && name[18] != '\0') 81280304Sjkim OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; 82238384Sjkim 83280304Sjkim return DI_WALK_TERMINATE; 84280304Sjkim } 85280304Sjkim /* This is expected to catch remaining UltraSPARCs, such as T1 */ 86280304Sjkim else if (!strncmp(name, "SUNW,UltraSPARC", 15)) { 87280304Sjkim OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; 88238384Sjkim 89280304Sjkim return DI_WALK_TERMINATE; 90280304Sjkim } 91238384Sjkim 92280304Sjkim return DI_WALK_CONTINUE; 93280304Sjkim} 94238384Sjkim 95238384Sjkimvoid OPENSSL_cpuid_setup(void) 96280304Sjkim{ 97280304Sjkim void *h; 98280304Sjkim char *e, si[256]; 99280304Sjkim static int trigger = 0; 100238384Sjkim 101280304Sjkim if (trigger) 102280304Sjkim return; 103280304Sjkim trigger = 1; 104238384Sjkim 105280304Sjkim if ((e = getenv("OPENSSL_sparcv9cap"))) { 106280304Sjkim OPENSSL_sparcv9cap_P = strtoul(e, NULL, 0); 107280304Sjkim return; 108280304Sjkim } 109238384Sjkim 110280304Sjkim if (sysinfo(SI_MACHINE, si, sizeof(si)) > 0) { 111280304Sjkim if (strcmp(si, "sun4v")) 112280304Sjkim /* FPU is preferred for all CPUs, but US-T1/2 */ 113280304Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU; 114280304Sjkim } 115238384Sjkim 116280304Sjkim if (sysinfo(SI_ISALIST, si, sizeof(si)) > 0) { 117280304Sjkim if (strstr(si, "+vis")) 118280304Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_VIS1; 119280304Sjkim if (strstr(si, "+vis2")) { 120280304Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_VIS2; 121280304Sjkim OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; 122280304Sjkim return; 123280304Sjkim } 124280304Sjkim } 125280304Sjkim# ifdef M_KEEP 126280304Sjkim /* 127280304Sjkim * Solaris libdevinfo.so.1 is effectively incomatible with 128280304Sjkim * libmalloc.so.1. Specifically, if application is linked with 129280304Sjkim * -lmalloc, it crashes upon startup with SIGSEGV in 130280304Sjkim * free(3LIBMALLOC) called by di_fini. Prior call to 131280304Sjkim * mallopt(M_KEEP,0) somehow helps... But not always... 132280304Sjkim */ 133280304Sjkim if ((h = dlopen(NULL, RTLD_LAZY))) { 134280304Sjkim union { 135280304Sjkim void *p; 136280304Sjkim int (*f) (int, int); 137280304Sjkim } sym; 138280304Sjkim if ((sym.p = dlsym(h, "mallopt"))) 139280304Sjkim (*sym.f) (M_KEEP, 0); 140280304Sjkim dlclose(h); 141280304Sjkim } 142280304Sjkim# endif 143280304Sjkim if ((h = dlopen("libdevinfo.so.1", RTLD_LAZY))) 144280304Sjkim do { 145280304Sjkim di_init_t di_init; 146280304Sjkim di_fini_t di_fini; 147280304Sjkim di_walk_node_t di_walk_node; 148280304Sjkim di_node_name_t di_node_name; 149280304Sjkim di_node_t root_node; 150238384Sjkim 151280304Sjkim if (!DLLINK(h, di_init)) 152280304Sjkim break; 153280304Sjkim if (!DLLINK(h, di_fini)) 154280304Sjkim break; 155280304Sjkim if (!DLLINK(h, di_walk_node)) 156280304Sjkim break; 157280304Sjkim if (!DLLINK(h, di_node_name)) 158280304Sjkim break; 159238384Sjkim 160280304Sjkim if ((root_node = (*di_init) ("/", DINFOSUBTREE)) != DI_NODE_NIL) { 161280304Sjkim (*di_walk_node) (root_node, DI_WALK_SIBFIRST, 162280304Sjkim di_node_name, walk_nodename); 163280304Sjkim (*di_fini) (root_node); 164280304Sjkim } 165280304Sjkim } while (0); 166238384Sjkim 167280304Sjkim if (h) 168280304Sjkim dlclose(h); 169280304Sjkim} 170238384Sjkim 171238384Sjkim#else 172238384Sjkim 173238384Sjkimstatic sigjmp_buf common_jmp; 174280304Sjkimstatic void common_handler(int sig) 175280304Sjkim{ 176280304Sjkim siglongjmp(common_jmp, sig); 177280304Sjkim} 178238384Sjkim 179238384Sjkimvoid OPENSSL_cpuid_setup(void) 180280304Sjkim{ 181280304Sjkim char *e; 182280304Sjkim struct sigaction common_act, ill_oact, bus_oact; 183280304Sjkim sigset_t all_masked, oset; 184280304Sjkim static int trigger = 0; 185238384Sjkim 186280304Sjkim if (trigger) 187280304Sjkim return; 188280304Sjkim trigger = 1; 189238384Sjkim 190280304Sjkim if ((e = getenv("OPENSSL_sparcv9cap"))) { 191280304Sjkim OPENSSL_sparcv9cap_P = strtoul(e, NULL, 0); 192280304Sjkim return; 193280304Sjkim } 194238384Sjkim 195280304Sjkim /* Initial value, fits UltraSPARC-I&II... */ 196280304Sjkim OPENSSL_sparcv9cap_P = SPARCV9_PREFER_FPU | SPARCV9_TICK_PRIVILEGED; 197238384Sjkim 198280304Sjkim sigfillset(&all_masked); 199280304Sjkim sigdelset(&all_masked, SIGILL); 200280304Sjkim sigdelset(&all_masked, SIGTRAP); 201280304Sjkim# ifdef SIGEMT 202280304Sjkim sigdelset(&all_masked, SIGEMT); 203280304Sjkim# endif 204280304Sjkim sigdelset(&all_masked, SIGFPE); 205280304Sjkim sigdelset(&all_masked, SIGBUS); 206280304Sjkim sigdelset(&all_masked, SIGSEGV); 207280304Sjkim sigprocmask(SIG_SETMASK, &all_masked, &oset); 208238384Sjkim 209280304Sjkim memset(&common_act, 0, sizeof(common_act)); 210280304Sjkim common_act.sa_handler = common_handler; 211280304Sjkim common_act.sa_mask = all_masked; 212238384Sjkim 213280304Sjkim sigaction(SIGILL, &common_act, &ill_oact); 214280304Sjkim sigaction(SIGBUS, &common_act, &bus_oact); /* T1 fails 16-bit ldda [on 215280304Sjkim * Linux] */ 216238384Sjkim 217280304Sjkim if (sigsetjmp(common_jmp, 1) == 0) { 218280304Sjkim _sparcv9_rdtick(); 219280304Sjkim OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; 220280304Sjkim } 221238384Sjkim 222280304Sjkim if (sigsetjmp(common_jmp, 1) == 0) { 223280304Sjkim _sparcv9_vis1_probe(); 224280304Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_VIS1; 225280304Sjkim /* detect UltraSPARC-Tx, see sparccpud.S for details... */ 226280304Sjkim if (_sparcv9_vis1_instrument() >= 12) 227280304Sjkim OPENSSL_sparcv9cap_P &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU); 228280304Sjkim else { 229280304Sjkim _sparcv9_vis2_probe(); 230280304Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_VIS2; 231280304Sjkim } 232280304Sjkim } 233238384Sjkim 234280304Sjkim if (sigsetjmp(common_jmp, 1) == 0) { 235280304Sjkim _sparcv9_fmadd_probe(); 236280304Sjkim OPENSSL_sparcv9cap_P |= SPARCV9_FMADD; 237280304Sjkim } 238238384Sjkim 239280304Sjkim sigaction(SIGBUS, &bus_oact, NULL); 240280304Sjkim sigaction(SIGILL, &ill_oact, NULL); 241238384Sjkim 242280304Sjkim sigprocmask(SIG_SETMASK, &oset, NULL); 243280304Sjkim} 244280304Sjkim 245238384Sjkim#endif 246