bb0c8e73a912488ab8ff1dfe9d85730052e7fb9f
[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
15 static int OPENSSL_sparcv9cap_P=SPARCV9_TICK_PRIVILEGED;
16
17 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)
18         {
19         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);
20         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);
21
22         if ((OPENSSL_sparcv9cap_P&(SPARCV9_PREFER_FPU|SPARCV9_VIS1)) ==
23                 (SPARCV9_PREFER_FPU|SPARCV9_VIS1))
24                 return bn_mul_mont_fpu(rp,ap,bp,np,n0,num);
25         else
26                 return bn_mul_mont_int(rp,ap,bp,np,n0,num);
27         }
28
29 unsigned long   _sparcv9_rdtick(void);
30 unsigned long   _sparcv9_vis1_probe(void);
31
32 unsigned long OPENSSL_rdtsc(void)
33         {
34         if (OPENSSL_sparcv9cap_P&SPARCV9_TICK_PRIVILEGED)
35 #if defined(__sun) && defined(__SVR4)
36                 return gethrtime();
37 #else
38                 return 0;
39 #endif
40         else
41                 return _sparcv9_rdtick();
42         }
43
44 #if defined(__sun) && defined(__SVR4)
45
46 #include <dlfcn.h>
47 #include <libdevinfo.h>
48 #include <sys/systeminfo.h>
49
50 typedef di_node_t (*di_init_t)(const char *,uint_t);
51 typedef void      (*di_fini_t)(di_node_t);
52 typedef char *    (*di_node_name_t)(di_node_t);
53 typedef int       (*di_walk_node_t)(di_node_t,uint_t,di_node_name_t,int (*)(di_node_t,di_node_name_t));
54
55 #define DLLINK(h,name) (name=(name##_t)dlsym((h),#name))
56
57 static int walk_nodename(di_node_t node, di_node_name_t di_node_name)
58         {
59         char *name = (*di_node_name)(node);
60
61         /* This is expected to catch all UltraSPARC flavors prior T1 */
62         if (!strcmp (name,"SUNW,UltraSPARC") ||
63             !strncmp(name,"SUNW,UltraSPARC-I",17))  /* covers II,III,IV */
64                 {
65                 OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU|SPARCV9_VIS1;
66
67                 /* %tick is privileged only on UltraSPARC-I/II, but not IIe */
68                 if (name[14]!='\0' && name[17]!='\0' && name[18]!='\0')
69                         OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED;
70
71                 return DI_WALK_TERMINATE;
72                 }
73         /* This is expected to catch remaining UltraSPARCs, such as T1 */
74         else if (!strncmp(name,"SUNW,UltraSPARC",15))
75                 {
76                 OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED;
77
78                 return DI_WALK_TERMINATE;
79                 }
80
81         return DI_WALK_CONTINUE;
82         }
83
84 void OPENSSL_cpuid_setup(void)
85         {
86         void *h;
87         char *e,si[256];
88         static int trigger=0;
89
90         if (trigger) return;
91         trigger=1;
92
93         if ((e=getenv("OPENSSL_sparcv9cap")))
94                 {
95                 OPENSSL_sparcv9cap_P=strtoul(e,NULL,0);
96                 return;
97                 }
98
99         if (sysinfo(SI_MACHINE,si,sizeof(si))>0)
100                 {
101                 if (strcmp(si,"sun4v"))
102                         /* FPU is preferred for all CPUs, but US-T1/2 */
103                         OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU;
104                 }
105
106         if (sysinfo(SI_ISALIST,si,sizeof(si))>0)
107                 {
108                 if (strstr(si,"+vis"))
109                         OPENSSL_sparcv9cap_P |= SPARCV9_VIS1;
110                 if (strstr(si,"+vis2"))
111                         {
112                         OPENSSL_sparcv9cap_P |= SPARCV9_VIS2;
113                         OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED;
114                         return;
115                         }
116                 }
117
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
126                 if (!DLLINK(h,di_init))         break;
127                 if (!DLLINK(h,di_fini))         break;
128                 if (!DLLINK(h,di_walk_node))    break;
129                 if (!DLLINK(h,di_node_name))    break;
130
131                 if ((root_node = (*di_init)("/",DINFOSUBTREE))!=DI_NODE_NIL)
132                         {
133                         (*di_walk_node)(root_node,DI_WALK_SIBFIRST,
134                                         di_node_name,walk_nodename);
135                         (*di_fini)(root_node);
136                         }
137                 } while(0);
138
139         if (h) dlclose(h);
140         }
141
142 #else
143
144 static sigjmp_buf common_jmp;
145 static void common_handler(int sig) { siglongjmp(common_jmp,sig); }
146
147 void OPENSSL_cpuid_setup(void)
148         {
149         char *e;
150         struct sigaction        common_act,ill_oact,bus_oact;
151         sigset_t                all_masked,oset;
152         int                     sig;
153  
154         if ((e=getenv("OPENSSL_sparcv9cap")))
155                 {
156                 OPENSSL_sparcv9cap_P=strtoul(e,NULL,0);
157                 return;
158                 }
159
160         /* For now we assume that the rest supports UltraSPARC-I* only */
161         OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU|SPARCV9_VIS1;
162
163         sigfillset(&all_masked);
164         sigdelset(&all_masked,SIGILL);
165         sigdelset(&all_masked,SIGTRAP);
166 #ifdef SIGEMT
167         sigdelset(&all_masked,SIGEMT);
168 #endif
169         sigdelset(&all_masked,SIGFPE);
170         sigdelset(&all_masked,SIGBUS);
171         sigdelset(&all_masked,SIGSEGV);
172         sigprocmask(SIG_SETMASK,&all_masked,&oset);
173
174         memset(&common_act,0,sizeof(common_act));
175         common_act.sa_handler = common_handler;
176         common_act.sa_mask    = all_masked;
177
178         sigaction(SIGILL,&common_act,&ill_oact);
179         if (sigsetjmp(common_jmp,0) == 0)
180                 {
181                 _sparcv9_rdtick();
182                 OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED;
183                 }
184         else
185                 {
186                 /* This happens on US-I&II, which have working VIS1
187                  * and fast FPU... In other words we are done... */
188                 OPENSSL_sparcv9cap_P |= SPARCV9_TICK_PRIVILEGED;
189                 sigaction(SIGILL,&ill_oact,NULL);
190                 sigprocmask(SIG_SETMASK,&oset,NULL);
191                 return;
192                 }
193         sigaction(SIGILL,&ill_oact,NULL);
194
195         sigaction(SIGILL,&common_act,&ill_oact);
196         sigaction(SIGBUS,&common_act,&bus_oact);/* T1 fails 16-bit ldda */
197         if ((sig=sigsetjmp(common_jmp,0)) == 0)
198                 {
199                 /* see sparccpud.S for details... */
200                 if (_sparcv9_vis1_probe() >= 12)
201                         OPENSSL_sparcv9cap_P &= ~SPARCV9_VIS1;
202                 }
203         else
204                 {
205                 OPENSSL_sparcv9cap_P &= ~SPARCV9_VIS1;
206                 }
207         sigaction(SIGBUS,&bus_oact,NULL);
208         sigaction(SIGILL,&ill_oact,NULL);
209
210         sigprocmask(SIG_SETMASK,&oset,NULL);
211         }
212
213 #endif