]>
Commit | Line | Data |
---|---|---|
c06b0f3d AP |
1 | #include <stdio.h> |
2 | #include <stdlib.h> | |
3 | #include <string.h> | |
40b6d493 DSH |
4 | #include <setjmp.h> |
5 | #include <signal.h> | |
c06b0f3d | 6 | #include <sys/time.h> |
48b7b96b | 7 | #include <unistd.h> |
c06b0f3d AP |
8 | #include <openssl/bn.h> |
9 | ||
48b7b96b | 10 | #include "sparc_arch.h" |
40b6d493 | 11 | |
48b7b96b | 12 | #if defined(__GNUC__) && defined(__linux) |
ae5c8664 | 13 | __attribute__ ((visibility("hidden"))) |
48b7b96b | 14 | #endif |
ae5c8664 MC |
15 | unsigned int OPENSSL_sparcv9cap_P[2] = { SPARCV9_TICK_PRIVILEGED, 0 }; |
16 | ||
17 | int 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 && | |
63 | (OPENSSL_sparcv9cap_P[0] & | |
64 | (SPARCV9_PREFER_FPU | SPARCV9_VIS1)) == | |
65 | (SPARCV9_PREFER_FPU | SPARCV9_VIS1)) | |
66 | return bn_mul_mont_fpu(rp, ap, bp, np, n0, num); | |
67 | } | |
68 | return bn_mul_mont_int(rp, ap, bp, np, n0, num); | |
69 | } | |
70 | ||
71 | unsigned long _sparcv9_rdtick(void); | |
72 | void _sparcv9_vis1_probe(void); | |
73 | unsigned long _sparcv9_vis1_instrument(void); | |
74 | void _sparcv9_vis2_probe(void); | |
75 | void _sparcv9_fmadd_probe(void); | |
76 | unsigned long _sparcv9_rdcfr(void); | |
77 | void _sparcv9_vis3_probe(void); | |
78 | unsigned long _sparcv9_random(void); | |
79 | size_t _sparcv9_vis1_instrument_bus(unsigned int *, size_t); | |
80 | size_t _sparcv9_vis1_instrument_bus2(unsigned int *, size_t, size_t); | |
40b6d493 | 81 | |
c06b0f3d | 82 | unsigned long OPENSSL_rdtsc(void) |
ae5c8664 MC |
83 | { |
84 | if (OPENSSL_sparcv9cap_P[0] & SPARCV9_TICK_PRIVILEGED) | |
c06b0f3d | 85 | #if defined(__sun) && defined(__SVR4) |
ae5c8664 | 86 | return gethrtime(); |
c06b0f3d | 87 | #else |
ae5c8664 | 88 | return 0; |
c06b0f3d | 89 | #endif |
ae5c8664 MC |
90 | else |
91 | return _sparcv9_rdtick(); | |
92 | } | |
93 | ||
94 | size_t OPENSSL_instrument_bus(unsigned int *out, size_t cnt) | |
95 | { | |
96 | if ((OPENSSL_sparcv9cap_P[0] & (SPARCV9_TICK_PRIVILEGED | SPARCV9_BLK)) == | |
97 | SPARCV9_BLK) | |
98 | return _sparcv9_vis1_instrument_bus(out, cnt); | |
99 | else | |
100 | return 0; | |
101 | } | |
102 | ||
103 | size_t OPENSSL_instrument_bus2(unsigned int *out, size_t cnt, size_t max) | |
104 | { | |
105 | if ((OPENSSL_sparcv9cap_P[0] & (SPARCV9_TICK_PRIVILEGED | SPARCV9_BLK)) == | |
106 | SPARCV9_BLK) | |
107 | return _sparcv9_vis1_instrument_bus2(out, cnt, max); | |
108 | else | |
109 | return 0; | |
110 | } | |
48b7b96b | 111 | |
387ed39f | 112 | #if 0 && defined(__sun) && defined(__SVR4) |
ae5c8664 MC |
113 | /* |
114 | * This code path is disabled, because of incompatibility of libdevinfo.so.1 | |
115 | * and libmalloc.so.1 (see below for details) | |
387ed39f | 116 | */ |
ae5c8664 MC |
117 | # include <malloc.h> |
118 | # include <dlfcn.h> | |
119 | # include <libdevinfo.h> | |
120 | # include <sys/systeminfo.h> | |
c06b0f3d | 121 | |
ae5c8664 MC |
122 | typedef di_node_t(*di_init_t) (const char *, uint_t); |
123 | typedef void (*di_fini_t) (di_node_t); | |
124 | typedef char *(*di_node_name_t) (di_node_t); | |
125 | typedef int (*di_walk_node_t) (di_node_t, uint_t, di_node_name_t, | |
126 | int (*)(di_node_t, di_node_name_t)); | |
c06b0f3d | 127 | |
ae5c8664 | 128 | # define DLLINK(h,name) (name=(name##_t)dlsym((h),#name)) |
c06b0f3d AP |
129 | |
130 | static int walk_nodename(di_node_t node, di_node_name_t di_node_name) | |
ae5c8664 MC |
131 | { |
132 | char *name = (*di_node_name) (node); | |
c06b0f3d | 133 | |
ae5c8664 MC |
134 | /* This is expected to catch all UltraSPARC flavors prior T1 */ |
135 | if (!strcmp(name, "SUNW,UltraSPARC") || | |
136 | /* covers II,III,IV */ | |
137 | !strncmp(name, "SUNW,UltraSPARC-I", 17)) { | |
138 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_PREFER_FPU | SPARCV9_VIS1; | |
c06b0f3d | 139 | |
ae5c8664 MC |
140 | /* %tick is privileged only on UltraSPARC-I/II, but not IIe */ |
141 | if (name[14] != '\0' && name[17] != '\0' && name[18] != '\0') | |
142 | OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED; | |
c06b0f3d | 143 | |
ae5c8664 MC |
144 | return DI_WALK_TERMINATE; |
145 | } | |
146 | /* This is expected to catch remaining UltraSPARCs, such as T1 */ | |
147 | else if (!strncmp(name, "SUNW,UltraSPARC", 15)) { | |
148 | OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED; | |
7a5dbeb7 | 149 | |
ae5c8664 MC |
150 | return DI_WALK_TERMINATE; |
151 | } | |
c06b0f3d | 152 | |
ae5c8664 MC |
153 | return DI_WALK_CONTINUE; |
154 | } | |
c06b0f3d AP |
155 | |
156 | void OPENSSL_cpuid_setup(void) | |
ae5c8664 MC |
157 | { |
158 | void *h; | |
159 | char *e, si[256]; | |
160 | static int trigger = 0; | |
161 | ||
162 | if (trigger) | |
163 | return; | |
164 | trigger = 1; | |
165 | ||
166 | if ((e = getenv("OPENSSL_sparcv9cap"))) { | |
167 | OPENSSL_sparcv9cap_P[0] = strtoul(e, NULL, 0); | |
168 | return; | |
169 | } | |
170 | ||
171 | if (sysinfo(SI_MACHINE, si, sizeof(si)) > 0) { | |
172 | if (strcmp(si, "sun4v")) | |
173 | /* FPU is preferred for all CPUs, but US-T1/2 */ | |
174 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_PREFER_FPU; | |
175 | } | |
176 | ||
177 | if (sysinfo(SI_ISALIST, si, sizeof(si)) > 0) { | |
178 | if (strstr(si, "+vis")) | |
179 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1 | SPARCV9_BLK; | |
180 | if (strstr(si, "+vis2")) { | |
181 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2; | |
182 | OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED; | |
183 | return; | |
184 | } | |
185 | } | |
186 | # ifdef M_KEEP | |
187 | /* | |
188 | * Solaris libdevinfo.so.1 is effectively incomatible with | |
189 | * libmalloc.so.1. Specifically, if application is linked with | |
190 | * -lmalloc, it crashes upon startup with SIGSEGV in | |
191 | * free(3LIBMALLOC) called by di_fini. Prior call to | |
192 | * mallopt(M_KEEP,0) somehow helps... But not always... | |
193 | */ | |
194 | if ((h = dlopen(NULL, RTLD_LAZY))) { | |
195 | union { | |
196 | void *p; | |
197 | int (*f) (int, int); | |
198 | } sym; | |
199 | if ((sym.p = dlsym(h, "mallopt"))) | |
200 | (*sym.f) (M_KEEP, 0); | |
201 | dlclose(h); | |
202 | } | |
203 | # endif | |
204 | if ((h = dlopen("libdevinfo.so.1", RTLD_LAZY))) | |
205 | do { | |
206 | di_init_t di_init; | |
207 | di_fini_t di_fini; | |
208 | di_walk_node_t di_walk_node; | |
209 | di_node_name_t di_node_name; | |
210 | di_node_t root_node; | |
211 | ||
212 | if (!DLLINK(h, di_init)) | |
213 | break; | |
214 | if (!DLLINK(h, di_fini)) | |
215 | break; | |
216 | if (!DLLINK(h, di_walk_node)) | |
217 | break; | |
218 | if (!DLLINK(h, di_node_name)) | |
219 | break; | |
220 | ||
221 | if ((root_node = (*di_init) ("/", DINFOSUBTREE)) != DI_NODE_NIL) { | |
222 | (*di_walk_node) (root_node, DI_WALK_SIBFIRST, | |
223 | di_node_name, walk_nodename); | |
224 | (*di_fini) (root_node); | |
225 | } | |
226 | } while (0); | |
227 | ||
228 | if (h) | |
229 | dlclose(h); | |
230 | } | |
c06b0f3d | 231 | |
a00e414f | 232 | #else |
c06b0f3d | 233 | |
40b6d493 | 234 | static sigjmp_buf common_jmp; |
ae5c8664 MC |
235 | static void common_handler(int sig) |
236 | { | |
237 | siglongjmp(common_jmp, sig); | |
238 | } | |
40b6d493 | 239 | |
15c62b0d AP |
240 | #if defined(__sun) && defined(__SVR4) |
241 | # if defined(__GNUC__) && __GNUC__>=2 | |
242 | extern unsigned int getisax(unsigned int vec[], unsigned int sz) __attribute__ ((weak)); | |
243 | # elif defined(__SUNPRO_C) | |
244 | #pragma weak getisax | |
245 | extern unsigned int getisax(unsigned int vec[], unsigned int sz); | |
246 | # else | |
247 | static unsigned int (*getisax) (unsigned int vec[], unsigned int sz) = NULL; | |
248 | # endif | |
249 | #endif | |
250 | ||
5d7324e4 | 251 | void OPENSSL_cpuid_setup(void) |
ae5c8664 MC |
252 | { |
253 | char *e; | |
254 | struct sigaction common_act, ill_oact, bus_oact; | |
255 | sigset_t all_masked, oset; | |
256 | static int trigger = 0; | |
257 | ||
258 | if (trigger) | |
259 | return; | |
260 | trigger = 1; | |
261 | ||
262 | if ((e = getenv("OPENSSL_sparcv9cap"))) { | |
263 | OPENSSL_sparcv9cap_P[0] = strtoul(e, NULL, 0); | |
264 | if ((e = strchr(e, ':'))) | |
265 | OPENSSL_sparcv9cap_P[1] = strtoul(e + 1, NULL, 0); | |
266 | return; | |
267 | } | |
268 | ||
15c62b0d AP |
269 | #if defined(__sun) && defined(__SVR4) |
270 | if (getisax != NULL) { | |
271 | unsigned int vec[1]; | |
272 | ||
273 | if (getisax (vec,1)) { | |
274 | if (vec[0]&0x0020) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1; | |
275 | if (vec[0]&0x0040) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2; | |
276 | if (vec[0]&0x0080) OPENSSL_sparcv9cap_P[0] |= SPARCV9_BLK; | |
277 | if (vec[0]&0x0100) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD; | |
278 | if (vec[0]&0x0400) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3; | |
279 | ||
280 | /* reconstruct %cfr copy */ | |
281 | OPENSSL_sparcv9cap_P[1] = (vec[0]>>17)&0x3ff; | |
282 | OPENSSL_sparcv9cap_P[1] |= (OPENSSL_sparcv9cap_P[1]&CFR_MONTMUL)<<1; | |
283 | if (vec[0]&0x20000000) OPENSSL_sparcv9cap_P[1] |= CFR_CRC32C; | |
284 | ||
285 | /* Some heuristics */ | |
286 | /* all known VIS2-capable CPUs have unprivileged tick counter */ | |
287 | if (OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS2) | |
288 | OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED; | |
289 | ||
290 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_PREFER_FPU; | |
291 | ||
292 | /* detect UltraSPARC-Tx, see sparccpud.S for details... */ | |
293 | if ((OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS1) && | |
294 | _sparcv9_vis1_instrument() >= 12) | |
295 | OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU); | |
296 | } | |
297 | ||
298 | if (sizeof(size_t) == 8) | |
299 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK; | |
300 | ||
301 | return; | |
302 | } | |
303 | #endif | |
304 | ||
ae5c8664 MC |
305 | /* Initial value, fits UltraSPARC-I&II... */ |
306 | OPENSSL_sparcv9cap_P[0] = SPARCV9_PREFER_FPU | SPARCV9_TICK_PRIVILEGED; | |
307 | ||
308 | sigfillset(&all_masked); | |
309 | sigdelset(&all_masked, SIGILL); | |
310 | sigdelset(&all_masked, SIGTRAP); | |
311 | # ifdef SIGEMT | |
312 | sigdelset(&all_masked, SIGEMT); | |
313 | # endif | |
314 | sigdelset(&all_masked, SIGFPE); | |
315 | sigdelset(&all_masked, SIGBUS); | |
316 | sigdelset(&all_masked, SIGSEGV); | |
317 | sigprocmask(SIG_SETMASK, &all_masked, &oset); | |
318 | ||
319 | memset(&common_act, 0, sizeof(common_act)); | |
320 | common_act.sa_handler = common_handler; | |
321 | common_act.sa_mask = all_masked; | |
322 | ||
323 | sigaction(SIGILL, &common_act, &ill_oact); | |
324 | sigaction(SIGBUS, &common_act, &bus_oact); /* T1 fails 16-bit ldda [on | |
325 | * Linux] */ | |
326 | ||
327 | if (sigsetjmp(common_jmp, 1) == 0) { | |
328 | _sparcv9_rdtick(); | |
329 | OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED; | |
330 | } | |
331 | ||
332 | if (sigsetjmp(common_jmp, 1) == 0) { | |
333 | _sparcv9_vis1_probe(); | |
334 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1 | SPARCV9_BLK; | |
335 | /* detect UltraSPARC-Tx, see sparccpud.S for details... */ | |
336 | if (_sparcv9_vis1_instrument() >= 12) | |
337 | OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU); | |
338 | else { | |
339 | _sparcv9_vis2_probe(); | |
340 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2; | |
341 | } | |
342 | } | |
343 | ||
344 | if (sigsetjmp(common_jmp, 1) == 0) { | |
345 | _sparcv9_fmadd_probe(); | |
346 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD; | |
347 | } | |
348 | ||
349 | /* | |
350 | * VIS3 flag is tested independently from VIS1, unlike VIS2 that is, | |
351 | * because VIS3 defines even integer instructions. | |
352 | */ | |
353 | if (sigsetjmp(common_jmp, 1) == 0) { | |
354 | _sparcv9_vis3_probe(); | |
355 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3; | |
356 | } | |
357 | # if 0 /* was planned at some point but never | |
358 | * implemented in hardware */ | |
359 | if (sigsetjmp(common_jmp, 1) == 0) { | |
360 | (void)_sparcv9_random(); | |
361 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_RANDOM; | |
362 | } | |
363 | # endif | |
364 | ||
365 | /* | |
366 | * In wait for better solution _sparcv9_rdcfr is masked by | |
367 | * VIS3 flag, because it goes to uninterruptable endless | |
368 | * loop on UltraSPARC II running Solaris. Things might be | |
369 | * different on Linux... | |
370 | */ | |
371 | if ((OPENSSL_sparcv9cap_P[0] & SPARCV9_VIS3) && | |
372 | sigsetjmp(common_jmp, 1) == 0) { | |
373 | OPENSSL_sparcv9cap_P[1] = (unsigned int)_sparcv9_rdcfr(); | |
374 | } | |
375 | ||
376 | sigaction(SIGBUS, &bus_oact, NULL); | |
377 | sigaction(SIGILL, &ill_oact, NULL); | |
378 | ||
379 | sigprocmask(SIG_SETMASK, &oset, NULL); | |
380 | ||
381 | if (sizeof(size_t) == 8) | |
382 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK; | |
383 | # ifdef __linux | |
384 | else { | |
385 | int ret = syscall(340); | |
386 | ||
387 | if (ret >= 0 && ret & 1) | |
388 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK; | |
389 | } | |
390 | # endif | |
391 | } | |
c06b0f3d | 392 | |
c06b0f3d | 393 | #endif |