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