X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fsparcv9cap.c;h=7ee6769120b21702dc248e9083326459a3db46e1;hp=bb0c8e73a912488ab8ff1dfe9d85730052e7fb9f;hb=b00f586a812c965a7a34938df00ff6eb2130754a;hpb=7c5889bf7a4ca21138e88d428fa3fa4ccc94789b diff --git a/crypto/sparcv9cap.c b/crypto/sparcv9cap.c index bb0c8e73a9..7ee6769120 100644 --- a/crypto/sparcv9cap.c +++ b/crypto/sparcv9cap.c @@ -4,34 +4,67 @@ #include #include #include +#include #include -#define SPARCV9_TICK_PRIVILEGED (1<<0) -#define SPARCV9_PREFER_FPU (1<<1) -#define SPARCV9_VIS1 (1<<2) -#define SPARCV9_VIS2 (1<<3) /* reserved */ -#define SPARCV9_FMADD (1<<4) /* reserved for SPARC64 V */ +#include "sparc_arch.h" -static int OPENSSL_sparcv9cap_P=SPARCV9_TICK_PRIVILEGED; +#if defined(__GNUC__) && defined(__linux) +__attribute__((visibility("hidden"))) +#endif +unsigned int OPENSSL_sparcv9cap_P[2]={SPARCV9_TICK_PRIVILEGED,0}; int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np,const BN_ULONG *n0, int num) { + int bn_mul_mont_vis3(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np,const BN_ULONG *n0, int num); 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); 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); - if ((OPENSSL_sparcv9cap_P&(SPARCV9_PREFER_FPU|SPARCV9_VIS1)) == - (SPARCV9_PREFER_FPU|SPARCV9_VIS1)) - return bn_mul_mont_fpu(rp,ap,bp,np,n0,num); - else - return bn_mul_mont_int(rp,ap,bp,np,n0,num); + if (!(num&1) && num>=6) + { + if ((num&15)==0 && num<=64 && + (OPENSSL_sparcv9cap_P[1]&(CFR_MONTMUL|CFR_MONTSQR))== + (CFR_MONTMUL|CFR_MONTSQR)) + { + typedef int (*bn_mul_mont_f)(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np,const BN_ULONG *n0); + int bn_mul_mont_t4_8(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np,const BN_ULONG *n0); + int bn_mul_mont_t4_16(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np,const BN_ULONG *n0); + int bn_mul_mont_t4_24(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np,const BN_ULONG *n0); + int bn_mul_mont_t4_32(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np,const BN_ULONG *n0); + static const bn_mul_mont_f funcs[4] = { + bn_mul_mont_t4_8, bn_mul_mont_t4_16, + bn_mul_mont_t4_24, bn_mul_mont_t4_32 }; + bn_mul_mont_f worker = funcs[num/16-1]; + + if ((*worker)(rp,ap,bp,np,n0)) return 1; + /* retry once and fall back */ + if ((*worker)(rp,ap,bp,np,n0)) return 1; + return bn_mul_mont_vis3(rp,ap,bp,np,n0,num); + } + if ((OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS3)) + return bn_mul_mont_vis3(rp,ap,bp,np,n0,num); + else if (num>=8 && + (OPENSSL_sparcv9cap_P[0]&(SPARCV9_PREFER_FPU|SPARCV9_VIS1)) == + (SPARCV9_PREFER_FPU|SPARCV9_VIS1)) + return bn_mul_mont_fpu(rp,ap,bp,np,n0,num); + } + return bn_mul_mont_int(rp,ap,bp,np,n0,num); } unsigned long _sparcv9_rdtick(void); -unsigned long _sparcv9_vis1_probe(void); +void _sparcv9_vis1_probe(void); +unsigned long _sparcv9_vis1_instrument(void); +void _sparcv9_vis2_probe(void); +void _sparcv9_fmadd_probe(void); +unsigned long _sparcv9_rdcfr(void); +void _sparcv9_vis3_probe(void); +unsigned long _sparcv9_random(void); +size_t _sparcv9_vis1_instrument_bus(unsigned int *,size_t); +size_t _sparcv9_vis1_instrument_bus2(unsigned int *,size_t,size_t); unsigned long OPENSSL_rdtsc(void) { - if (OPENSSL_sparcv9cap_P&SPARCV9_TICK_PRIVILEGED) + if (OPENSSL_sparcv9cap_P[0]&SPARCV9_TICK_PRIVILEGED) #if defined(__sun) && defined(__SVR4) return gethrtime(); #else @@ -41,8 +74,29 @@ unsigned long OPENSSL_rdtsc(void) return _sparcv9_rdtick(); } -#if defined(__sun) && defined(__SVR4) +size_t OPENSSL_instrument_bus(unsigned int *out,size_t cnt) + { + if ((OPENSSL_sparcv9cap_P[0]&(SPARCV9_TICK_PRIVILEGED|SPARCV9_BLK)) == + SPARCV9_BLK) + return _sparcv9_vis1_instrument_bus(out,cnt); + else + return 0; + } + +size_t OPENSSL_instrument_bus2(unsigned int *out,size_t cnt,size_t max) + { + if ((OPENSSL_sparcv9cap_P[0]&(SPARCV9_TICK_PRIVILEGED|SPARCV9_BLK)) == + SPARCV9_BLK) + return _sparcv9_vis1_instrument_bus2(out,cnt,max); + else + return 0; + } +#if 0 && defined(__sun) && defined(__SVR4) +/* This code path is disabled, because of incompatibility of + * libdevinfo.so.1 and libmalloc.so.1 (see below for details) + */ +#include #include #include #include @@ -62,18 +116,18 @@ static int walk_nodename(di_node_t node, di_node_name_t di_node_name) if (!strcmp (name,"SUNW,UltraSPARC") || !strncmp(name,"SUNW,UltraSPARC-I",17)) /* covers II,III,IV */ { - OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU|SPARCV9_VIS1; + OPENSSL_sparcv9cap_P[0] |= SPARCV9_PREFER_FPU|SPARCV9_VIS1; /* %tick is privileged only on UltraSPARC-I/II, but not IIe */ if (name[14]!='\0' && name[17]!='\0' && name[18]!='\0') - OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; + OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED; return DI_WALK_TERMINATE; } /* This is expected to catch remaining UltraSPARCs, such as T1 */ else if (!strncmp(name,"SUNW,UltraSPARC",15)) { - OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; + OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED; return DI_WALK_TERMINATE; } @@ -92,7 +146,7 @@ void OPENSSL_cpuid_setup(void) if ((e=getenv("OPENSSL_sparcv9cap"))) { - OPENSSL_sparcv9cap_P=strtoul(e,NULL,0); + OPENSSL_sparcv9cap_P[0]=strtoul(e,NULL,0); return; } @@ -100,21 +154,35 @@ void OPENSSL_cpuid_setup(void) { if (strcmp(si,"sun4v")) /* FPU is preferred for all CPUs, but US-T1/2 */ - OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU; + OPENSSL_sparcv9cap_P[0] |= SPARCV9_PREFER_FPU; } if (sysinfo(SI_ISALIST,si,sizeof(si))>0) { if (strstr(si,"+vis")) - OPENSSL_sparcv9cap_P |= SPARCV9_VIS1; + OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1|SPARCV9_BLK; if (strstr(si,"+vis2")) { - OPENSSL_sparcv9cap_P |= SPARCV9_VIS2; - OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; + OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2; + OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED; return; } } - +#ifdef M_KEEP + /* + * Solaris libdevinfo.so.1 is effectively incomatible with + * libmalloc.so.1. Specifically, if application is linked with + * -lmalloc, it crashes upon startup with SIGSEGV in + * free(3LIBMALLOC) called by di_fini. Prior call to + * mallopt(M_KEEP,0) somehow helps... But not always... + */ + if ((h = dlopen(NULL,RTLD_LAZY))) + { + union { void *p; int (*f)(int,int); } sym; + if ((sym.p = dlsym(h,"mallopt"))) (*sym.f)(M_KEEP,0); + dlclose(h); + } +#endif if ((h = dlopen("libdevinfo.so.1",RTLD_LAZY))) do { di_init_t di_init; @@ -149,16 +217,21 @@ void OPENSSL_cpuid_setup(void) char *e; struct sigaction common_act,ill_oact,bus_oact; sigset_t all_masked,oset; - int sig; + static int trigger=0; + + if (trigger) return; + trigger=1; if ((e=getenv("OPENSSL_sparcv9cap"))) { - OPENSSL_sparcv9cap_P=strtoul(e,NULL,0); + OPENSSL_sparcv9cap_P[0]=strtoul(e,NULL,0); + if ((e=strchr(e,':'))) + OPENSSL_sparcv9cap_P[1]=strtoul(e+1,NULL,0); return; } - /* For now we assume that the rest supports UltraSPARC-I* only */ - OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU|SPARCV9_VIS1; + /* Initial value, fits UltraSPARC-I&II... */ + OPENSSL_sparcv9cap_P[0] = SPARCV9_PREFER_FPU|SPARCV9_TICK_PRIVILEGED; sigfillset(&all_masked); sigdelset(&all_masked,SIGILL); @@ -176,38 +249,80 @@ void OPENSSL_cpuid_setup(void) common_act.sa_mask = all_masked; sigaction(SIGILL,&common_act,&ill_oact); - if (sigsetjmp(common_jmp,0) == 0) + sigaction(SIGBUS,&common_act,&bus_oact);/* T1 fails 16-bit ldda [on Linux] */ + + if (sigsetjmp(common_jmp,1) == 0) { _sparcv9_rdtick(); - OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED; + OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED; } - else + + if (sigsetjmp(common_jmp,1) == 0) { - /* This happens on US-I&II, which have working VIS1 - * and fast FPU... In other words we are done... */ - OPENSSL_sparcv9cap_P |= SPARCV9_TICK_PRIVILEGED; - sigaction(SIGILL,&ill_oact,NULL); - sigprocmask(SIG_SETMASK,&oset,NULL); - return; + _sparcv9_vis1_probe(); + OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1|SPARCV9_BLK; + /* detect UltraSPARC-Tx, see sparccpud.S for details... */ + if (_sparcv9_vis1_instrument() >= 12) + OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1|SPARCV9_PREFER_FPU); + else + { + _sparcv9_vis2_probe(); + OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2; + } } - sigaction(SIGILL,&ill_oact,NULL); - sigaction(SIGILL,&common_act,&ill_oact); - sigaction(SIGBUS,&common_act,&bus_oact);/* T1 fails 16-bit ldda */ - if ((sig=sigsetjmp(common_jmp,0)) == 0) + if (sigsetjmp(common_jmp,1) == 0) { - /* see sparccpud.S for details... */ - if (_sparcv9_vis1_probe() >= 12) - OPENSSL_sparcv9cap_P &= ~SPARCV9_VIS1; + _sparcv9_fmadd_probe(); + OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD; } - else + + /* + * VIS3 flag is tested independently from VIS1, unlike VIS2 that is, + * because VIS3 defines even integer instructions. + */ + if (sigsetjmp(common_jmp,1) == 0) + { + _sparcv9_vis3_probe(); + OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3; + } + +#if 0 /* was planned at some point but never implemented in hardware */ + if (sigsetjmp(common_jmp,1) == 0) + { + (void)_sparcv9_random(); + OPENSSL_sparcv9cap_P[0] |= SPARCV9_RANDOM; + } +#endif + + /* + * In wait for better solution _sparcv9_rdcfr is masked by + * VIS3 flag, because it goes to uninterruptable endless + * loop on UltraSPARC II running Solaris. Things might be + * different on Linux... + */ + if ((OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS3) && + sigsetjmp(common_jmp,1) == 0) { - OPENSSL_sparcv9cap_P &= ~SPARCV9_VIS1; + OPENSSL_sparcv9cap_P[1] = (unsigned int)_sparcv9_rdcfr(); } + sigaction(SIGBUS,&bus_oact,NULL); sigaction(SIGILL,&ill_oact,NULL); sigprocmask(SIG_SETMASK,&oset,NULL); + + if (sizeof(size_t)==8) + OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK; +#ifdef __linux + else + { + int ret = syscall(340); + + if (ret>=0 && ret&1) + OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK; + } +#endif } #endif