Update from 1.0.0-stable
[openssl.git] / crypto / sparcv9cap.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/time.h>
5 #include <openssl/bn.h>
6
7 #define SPARCV9_TICK_PRIVILEGED (1<<0)
8 #define SPARCV9_PREFER_FPU      (1<<1)
9 #define SPARCV9_VIS1            (1<<2)
10 #define SPARCV9_VIS2            (1<<3)  /* reserved */
11 #define SPARCV9_FMADD           (1<<4)  /* reserved for SPARC64 V */
12 static int OPENSSL_sparcv9cap_P=SPARCV9_TICK_PRIVILEGED;
13
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
19         if ((OPENSSL_sparcv9cap_P&(SPARCV9_PREFER_FPU|SPARCV9_VIS1)) ==
20                 (SPARCV9_PREFER_FPU|SPARCV9_VIS1))
21                 return bn_mul_mont_fpu(rp,ap,bp,np,n0,num);
22         else
23                 return bn_mul_mont_int(rp,ap,bp,np,n0,num);
24         }
25
26 unsigned long OPENSSL_rdtsc(void)
27         {
28         unsigned long _sparcv9_rdtick(void);
29
30         if (OPENSSL_sparcv9cap_P&SPARCV9_TICK_PRIVILEGED)
31 #if defined(__sun) && defined(__SVR4)
32                 return gethrtime();
33 #else
34                 return 0;
35 #endif
36         else
37                 return _sparcv9_rdtick();
38         }
39
40 #if defined(__sun) && defined(__SVR4)
41
42 #include <dlfcn.h>
43 #include <libdevinfo.h>
44 #include <sys/systeminfo.h>
45
46 typedef di_node_t (*di_init_t)(const char *,uint_t);
47 typedef void      (*di_fini_t)(di_node_t);
48 typedef char *    (*di_node_name_t)(di_node_t);
49 typedef int       (*di_walk_node_t)(di_node_t,uint_t,di_node_name_t,int (*)(di_node_t,di_node_name_t));
50
51 #define DLLINK(h,name) (name=(name##_t)dlsym((h),#name))
52
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
57         /* This is expected to catch all UltraSPARC flavors prior T1 */
58         if (!strcmp (name,"SUNW,UltraSPARC") ||
59             !strncmp(name,"SUNW,UltraSPARC-I",17))  /* covers II,III,IV */
60                 {
61                 OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU|SPARCV9_VIS1;
62
63                 /* %tick is privileged only on UltraSPARC-I/II, but not IIe */
64                 if (name[14]!='\0' && name[17]!='\0' && name[18]!='\0')
65                         OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED;
66
67                 return DI_WALK_TERMINATE;
68                 }
69         /* This is expected to catch remaining UltraSPARCs, such as T1 */
70         else if (!strncmp(name,"SUNW,UltraSPARC",15))
71                 {
72                 OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED;
73
74                 return DI_WALK_TERMINATE;
75                 }
76
77         return DI_WALK_CONTINUE;
78         }
79
80 void OPENSSL_cpuid_setup(void)
81         {
82         void *h;
83         char *e,si[256];
84         static int trigger=0;
85
86         if (trigger) return;
87         trigger=1;
88
89         if ((e=getenv("OPENSSL_sparcv9cap")))
90                 {
91                 OPENSSL_sparcv9cap_P=strtoul(e,NULL,0);
92                 return;
93                 }
94
95         if (sysinfo(SI_MACHINE,si,sizeof(si))>0)
96                 {
97                 if (strcmp(si,"sun4v"))
98                         /* FPU is preferred for all CPUs, but US-T1/2 */
99                         OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU;
100                 }
101
102         if (sysinfo(SI_ISALIST,si,sizeof(si))>0)
103                 {
104                 if (strstr(si,"+vis"))
105                         OPENSSL_sparcv9cap_P |= SPARCV9_VIS1;
106                 if (strstr(si,"+vis2"))
107                         {
108                         OPENSSL_sparcv9cap_P |= SPARCV9_VIS2;
109                         OPENSSL_sparcv9cap_P &= ~SPARCV9_TICK_PRIVILEGED;
110                         return;
111                         }
112                 }
113
114         if ((h = dlopen("libdevinfo.so.1",RTLD_LAZY))) do
115                 {
116                 di_init_t       di_init;
117                 di_fini_t       di_fini;
118                 di_walk_node_t  di_walk_node;
119                 di_node_name_t  di_node_name;
120                 di_node_t       root_node;
121
122                 if (!DLLINK(h,di_init))         break;
123                 if (!DLLINK(h,di_fini))         break;
124                 if (!DLLINK(h,di_walk_node))    break;
125                 if (!DLLINK(h,di_node_name))    break;
126
127                 if ((root_node = (*di_init)("/",DINFOSUBTREE))!=DI_NODE_NIL)
128                         {
129                         (*di_walk_node)(root_node,DI_WALK_SIBFIRST,
130                                         di_node_name,walk_nodename);
131                         (*di_fini)(root_node);
132                         }
133                 } while(0);
134
135         if (h) dlclose(h);
136         }
137
138 #else
139
140 void OPENSSL_cpuid_setup(void)
141         {
142         char *e;
143  
144         if ((e=getenv("OPENSSL_sparcv9cap")))
145                 {
146                 OPENSSL_sparcv9cap_P=strtoul(e,NULL,0);
147                 return;
148                 }
149
150         /* For now we assume that the rest supports UltraSPARC-I* only */
151         OPENSSL_sparcv9cap_P |= SPARCV9_PREFER_FPU|SPARCV9_VIS1;
152         }
153
154 #endif