sparcv9cap.c 6.0 KB

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