]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/sparcv9cap.c
Copyright consolidation 08/10
[thirdparty/openssl.git] / crypto / sparcv9cap.c
CommitLineData
c06b0f3d
AP
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
c32fcca6
AP
4#include <setjmp.h>
5#include <signal.h>
c06b0f3d 6#include <sys/time.h>
68c06bf6 7#include <unistd.h>
c06b0f3d
AP
8#include <openssl/bn.h>
9
1fda639a 10#include "sparc_arch.h"
c32fcca6 11
1fda639a 12#if defined(__GNUC__) && defined(__linux)
0f113f3e 13__attribute__ ((visibility("hidden")))
1fda639a 14#endif
0f113f3e
MC
15unsigned int OPENSSL_sparcv9cap_P[2] = { SPARCV9_TICK_PRIVILEGED, 0 };
16
17int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
18 const BN_ULONG *np, const BN_ULONG *n0, int num)
19{
20 int bn_mul_mont_vis3(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
21 const BN_ULONG *np, const BN_ULONG *n0, int num);
22 int bn_mul_mont_fpu(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
23 const BN_ULONG *np, const BN_ULONG *n0, int num);
24 int bn_mul_mont_int(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
25 const BN_ULONG *np, const BN_ULONG *n0, int num);
26
27 if (!(num & 1) && num >= 6) {
28 if ((num & 15) == 0 && num <= 64 &&
29 (OPENSSL_sparcv9cap_P[1] & (CFR_MONTMUL | CFR_MONTSQR)) ==
30 (CFR_MONTMUL | CFR_MONTSQR)) {
31 typedef int (*bn_mul_mont_f) (BN_ULONG *rp, const BN_ULONG *ap,
32 const BN_ULONG *bp,
33 const BN_ULONG *np,
34 const BN_ULONG *n0);
35 int bn_mul_mont_t4_8(BN_ULONG *rp, const BN_ULONG *ap,
36 const BN_ULONG *bp, const BN_ULONG *np,
37 const BN_ULONG *n0);
38 int bn_mul_mont_t4_16(BN_ULONG *rp, const BN_ULONG *ap,
39 const BN_ULONG *bp, const BN_ULONG *np,
40 const BN_ULONG *n0);
41 int bn_mul_mont_t4_24(BN_ULONG *rp, const BN_ULONG *ap,
42 const BN_ULONG *bp, const BN_ULONG *np,
43 const BN_ULONG *n0);
44 int bn_mul_mont_t4_32(BN_ULONG *rp, const BN_ULONG *ap,
45 const BN_ULONG *bp, const BN_ULONG *np,
46 const BN_ULONG *n0);
47 static const bn_mul_mont_f funcs[4] = {
48 bn_mul_mont_t4_8, bn_mul_mont_t4_16,
49 bn_mul_mont_t4_24, bn_mul_mont_t4_32
50 };
51 bn_mul_mont_f worker = funcs[num / 16 - 1];
52
53 if ((*worker) (rp, ap, bp, np, n0))
54 return 1;
55 /* retry once and fall back */
56 if ((*worker) (rp, ap, bp, np, n0))
57 return 1;
58 return bn_mul_mont_vis3(rp, ap, bp, np, n0, num);
59 }
60 if ((OPENSSL_sparcv9cap_P[0] & SPARCV9_VIS3))
61 return bn_mul_mont_vis3(rp, ap, bp, np, n0, num);
62 else if (num >= 8 &&
33ea23dc
AP
63 /*
64 * bn_mul_mont_fpu doesn't use FMADD, we just use the
65 * flag to detect when FPU path is preferable in cases
66 * when current heuristics is unreliable. [it works
67 * out because FMADD-capable processors where FPU
68 * code path is undesirable are also VIS3-capable and
69 * VIS3 code path takes precedence.]
70 */
71 ( (OPENSSL_sparcv9cap_P[0] & SPARCV9_FMADD) ||
72 (OPENSSL_sparcv9cap_P[0] &
73 (SPARCV9_PREFER_FPU | SPARCV9_VIS1)) ==
74 (SPARCV9_PREFER_FPU | SPARCV9_VIS1) ))
0f113f3e
MC
75 return bn_mul_mont_fpu(rp, ap, bp, np, n0, num);
76 }
77 return bn_mul_mont_int(rp, ap, bp, np, n0, num);
78}
79
80unsigned long _sparcv9_rdtick(void);
81void _sparcv9_vis1_probe(void);
82unsigned long _sparcv9_vis1_instrument(void);
83void _sparcv9_vis2_probe(void);
84void _sparcv9_fmadd_probe(void);
85unsigned long _sparcv9_rdcfr(void);
86void _sparcv9_vis3_probe(void);
87unsigned long _sparcv9_random(void);
88size_t _sparcv9_vis1_instrument_bus(unsigned int *, size_t);
89size_t _sparcv9_vis1_instrument_bus2(unsigned int *, size_t, size_t);
c32fcca6 90
c06b0f3d 91unsigned long OPENSSL_rdtsc(void)
0f113f3e
MC
92{
93 if (OPENSSL_sparcv9cap_P[0] & SPARCV9_TICK_PRIVILEGED)
c06b0f3d 94#if defined(__sun) && defined(__SVR4)
0f113f3e 95 return gethrtime();
c06b0f3d 96#else
0f113f3e 97 return 0;
c06b0f3d 98#endif
0f113f3e
MC
99 else
100 return _sparcv9_rdtick();
101}
102
103size_t OPENSSL_instrument_bus(unsigned int *out, size_t cnt)
104{
105 if ((OPENSSL_sparcv9cap_P[0] & (SPARCV9_TICK_PRIVILEGED | SPARCV9_BLK)) ==
106 SPARCV9_BLK)
107 return _sparcv9_vis1_instrument_bus(out, cnt);
108 else
109 return 0;
110}
111
112size_t OPENSSL_instrument_bus2(unsigned int *out, size_t cnt, size_t max)
113{
114 if ((OPENSSL_sparcv9cap_P[0] & (SPARCV9_TICK_PRIVILEGED | SPARCV9_BLK)) ==
115 SPARCV9_BLK)
116 return _sparcv9_vis1_instrument_bus2(out, cnt, max);
117 else
118 return 0;
119}
5fabb88a 120
c32fcca6 121static sigjmp_buf common_jmp;
0f113f3e
MC
122static void common_handler(int sig)
123{
124 siglongjmp(common_jmp, sig);
125}
c32fcca6 126
2238e0e4
AP
127#if defined(__sun) && defined(__SVR4)
128# if defined(__GNUC__) && __GNUC__>=2
129extern unsigned int getisax(unsigned int vec[], unsigned int sz) __attribute__ ((weak));
130# elif defined(__SUNPRO_C)
131#pragma weak getisax
132extern unsigned int getisax(unsigned int vec[], unsigned int sz);
133# else
134static unsigned int (*getisax) (unsigned int vec[], unsigned int sz) = NULL;
135# endif
136#endif
137
5d7324e4 138void OPENSSL_cpuid_setup(void)
0f113f3e
MC
139{
140 char *e;
141 struct sigaction common_act, ill_oact, bus_oact;
142 sigset_t all_masked, oset;
143 static int trigger = 0;
144
145 if (trigger)
146 return;
147 trigger = 1;
148
149 if ((e = getenv("OPENSSL_sparcv9cap"))) {
150 OPENSSL_sparcv9cap_P[0] = strtoul(e, NULL, 0);
151 if ((e = strchr(e, ':')))
152 OPENSSL_sparcv9cap_P[1] = strtoul(e + 1, NULL, 0);
153 return;
154 }
155
2238e0e4
AP
156#if defined(__sun) && defined(__SVR4)
157 if (getisax != NULL) {
158 unsigned int vec[1];
159
160 if (getisax (vec,1)) {
299ccadc
AP
161 if (vec[0]&0x00020) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1;
162 if (vec[0]&0x00040) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2;
163 if (vec[0]&0x00080) OPENSSL_sparcv9cap_P[0] |= SPARCV9_BLK;
164 if (vec[0]&0x00100) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD;
165 if (vec[0]&0x00400) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3;
166 if (vec[0]&0x01000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJHPCACE;
167 if (vec[0]&0x02000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJDESX;
168 if (vec[0]&0x08000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_IMA;
4400f6c6 169 if (vec[0]&0x10000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJAESX;
299ccadc 170 if (vec[1]&0x00008) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS4;
2238e0e4
AP
171
172 /* reconstruct %cfr copy */
173 OPENSSL_sparcv9cap_P[1] = (vec[0]>>17)&0x3ff;
174 OPENSSL_sparcv9cap_P[1] |= (OPENSSL_sparcv9cap_P[1]&CFR_MONTMUL)<<1;
175 if (vec[0]&0x20000000) OPENSSL_sparcv9cap_P[1] |= CFR_CRC32C;
299ccadc
AP
176 if (vec[1]&0x00000020) OPENSSL_sparcv9cap_P[1] |= CFR_XMPMUL;
177 if (vec[1]&0x00000040)
178 OPENSSL_sparcv9cap_P[1] |= CFR_XMONTMUL|CFR_XMONTSQR;
2238e0e4
AP
179
180 /* Some heuristics */
181 /* all known VIS2-capable CPUs have unprivileged tick counter */
182 if (OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS2)
183 OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED;
184
185 OPENSSL_sparcv9cap_P[0] |= SPARCV9_PREFER_FPU;
186
187 /* detect UltraSPARC-Tx, see sparccpud.S for details... */
188 if ((OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS1) &&
189 _sparcv9_vis1_instrument() >= 12)
190 OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU);
191 }
192
193 if (sizeof(size_t) == 8)
194 OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK;
195
196 return;
197 }
198#endif
199
0f113f3e
MC
200 /* Initial value, fits UltraSPARC-I&II... */
201 OPENSSL_sparcv9cap_P[0] = SPARCV9_PREFER_FPU | SPARCV9_TICK_PRIVILEGED;
202
203 sigfillset(&all_masked);
204 sigdelset(&all_masked, SIGILL);
205 sigdelset(&all_masked, SIGTRAP);
206# ifdef SIGEMT
207 sigdelset(&all_masked, SIGEMT);
208# endif
209 sigdelset(&all_masked, SIGFPE);
210 sigdelset(&all_masked, SIGBUS);
211 sigdelset(&all_masked, SIGSEGV);
212 sigprocmask(SIG_SETMASK, &all_masked, &oset);
213
214 memset(&common_act, 0, sizeof(common_act));
215 common_act.sa_handler = common_handler;
216 common_act.sa_mask = all_masked;
217
218 sigaction(SIGILL, &common_act, &ill_oact);
219 sigaction(SIGBUS, &common_act, &bus_oact); /* T1 fails 16-bit ldda [on
220 * Linux] */
221
222 if (sigsetjmp(common_jmp, 1) == 0) {
223 _sparcv9_rdtick();
224 OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED;
225 }
226
227 if (sigsetjmp(common_jmp, 1) == 0) {
228 _sparcv9_vis1_probe();
229 OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1 | SPARCV9_BLK;
230 /* detect UltraSPARC-Tx, see sparccpud.S for details... */
231 if (_sparcv9_vis1_instrument() >= 12)
232 OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU);
233 else {
234 _sparcv9_vis2_probe();
235 OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2;
236 }
237 }
238
239 if (sigsetjmp(common_jmp, 1) == 0) {
240 _sparcv9_fmadd_probe();
241 OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD;
242 }
243
244 /*
245 * VIS3 flag is tested independently from VIS1, unlike VIS2 that is,
246 * because VIS3 defines even integer instructions.
247 */
248 if (sigsetjmp(common_jmp, 1) == 0) {
249 _sparcv9_vis3_probe();
250 OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3;
251 }
0f113f3e 252
4400f6c6
AP
253 if (sigsetjmp(common_jmp, 1) == 0) {
254 _sparcv9_fjaesx_probe();
255 OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJAESX;
256 }
257
0f113f3e
MC
258 /*
259 * In wait for better solution _sparcv9_rdcfr is masked by
260 * VIS3 flag, because it goes to uninterruptable endless
261 * loop on UltraSPARC II running Solaris. Things might be
262 * different on Linux...
263 */
264 if ((OPENSSL_sparcv9cap_P[0] & SPARCV9_VIS3) &&
265 sigsetjmp(common_jmp, 1) == 0) {
266 OPENSSL_sparcv9cap_P[1] = (unsigned int)_sparcv9_rdcfr();
267 }
268
269 sigaction(SIGBUS, &bus_oact, NULL);
270 sigaction(SIGILL, &ill_oact, NULL);
271
272 sigprocmask(SIG_SETMASK, &oset, NULL);
273
274 if (sizeof(size_t) == 8)
275 OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK;
276# ifdef __linux
277 else {
278 int ret = syscall(340);
279
280 if (ret >= 0 && ret & 1)
281 OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK;
282 }
283# endif
284}