1 | /*
|
---|
2 | * Copyright 2005-2021 The OpenSSL Project Authors. All Rights Reserved.
|
---|
3 | *
|
---|
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use
|
---|
5 | * this file except in compliance with the License. You can obtain a copy
|
---|
6 | * in the file LICENSE in the source distribution or at
|
---|
7 | * https://www.openssl.org/source/license.html
|
---|
8 | */
|
---|
9 |
|
---|
10 | #include <stdio.h>
|
---|
11 | #include <stdlib.h>
|
---|
12 | #include <string.h>
|
---|
13 | #include <setjmp.h>
|
---|
14 | #include <signal.h>
|
---|
15 | #include <sys/time.h>
|
---|
16 | #include <unistd.h>
|
---|
17 | #include <openssl/bn.h>
|
---|
18 | #include "internal/cryptlib.h"
|
---|
19 | #include "crypto/sparc_arch.h"
|
---|
20 |
|
---|
21 | #if defined(__GNUC__) && defined(__linux)
|
---|
22 | __attribute__ ((visibility("hidden")))
|
---|
23 | #endif
|
---|
24 | unsigned int OPENSSL_sparcv9cap_P[2] = { SPARCV9_TICK_PRIVILEGED, 0 };
|
---|
25 |
|
---|
26 | unsigned long _sparcv9_rdtick(void);
|
---|
27 | void _sparcv9_vis1_probe(void);
|
---|
28 | unsigned long _sparcv9_vis1_instrument(void);
|
---|
29 | void _sparcv9_vis2_probe(void);
|
---|
30 | void _sparcv9_fmadd_probe(void);
|
---|
31 | unsigned long _sparcv9_rdcfr(void);
|
---|
32 | void _sparcv9_vis3_probe(void);
|
---|
33 | void _sparcv9_fjaesx_probe(void);
|
---|
34 | unsigned long _sparcv9_random(void);
|
---|
35 | size_t _sparcv9_vis1_instrument_bus(unsigned int *, size_t);
|
---|
36 | size_t _sparcv9_vis1_instrument_bus2(unsigned int *, size_t, size_t);
|
---|
37 |
|
---|
38 | uint32_t OPENSSL_rdtsc(void)
|
---|
39 | {
|
---|
40 | if (OPENSSL_sparcv9cap_P[0] & SPARCV9_TICK_PRIVILEGED)
|
---|
41 | #if defined(__sun) && defined(__SVR4)
|
---|
42 | return gethrtime();
|
---|
43 | #else
|
---|
44 | return 0;
|
---|
45 | #endif
|
---|
46 | else
|
---|
47 | return _sparcv9_rdtick();
|
---|
48 | }
|
---|
49 |
|
---|
50 | size_t OPENSSL_instrument_bus(unsigned int *out, size_t cnt)
|
---|
51 | {
|
---|
52 | if ((OPENSSL_sparcv9cap_P[0] & (SPARCV9_TICK_PRIVILEGED | SPARCV9_BLK)) ==
|
---|
53 | SPARCV9_BLK)
|
---|
54 | return _sparcv9_vis1_instrument_bus(out, cnt);
|
---|
55 | else
|
---|
56 | return 0;
|
---|
57 | }
|
---|
58 |
|
---|
59 | size_t OPENSSL_instrument_bus2(unsigned int *out, size_t cnt, size_t max)
|
---|
60 | {
|
---|
61 | if ((OPENSSL_sparcv9cap_P[0] & (SPARCV9_TICK_PRIVILEGED | SPARCV9_BLK)) ==
|
---|
62 | SPARCV9_BLK)
|
---|
63 | return _sparcv9_vis1_instrument_bus2(out, cnt, max);
|
---|
64 | else
|
---|
65 | return 0;
|
---|
66 | }
|
---|
67 |
|
---|
68 | static sigjmp_buf common_jmp;
|
---|
69 | static void common_handler(int sig)
|
---|
70 | {
|
---|
71 | siglongjmp(common_jmp, sig);
|
---|
72 | }
|
---|
73 |
|
---|
74 | #if defined(__sun) && defined(__SVR4)
|
---|
75 | # if defined(__GNUC__) && __GNUC__>=2
|
---|
76 | extern unsigned int getisax(unsigned int vec[], unsigned int sz) __attribute__ ((weak));
|
---|
77 | # elif defined(__SUNPRO_C)
|
---|
78 | #pragma weak getisax
|
---|
79 | extern unsigned int getisax(unsigned int vec[], unsigned int sz);
|
---|
80 | # else
|
---|
81 | static unsigned int (*getisax) (unsigned int vec[], unsigned int sz) = NULL;
|
---|
82 | # endif
|
---|
83 | #endif
|
---|
84 |
|
---|
85 | void OPENSSL_cpuid_setup(void)
|
---|
86 | {
|
---|
87 | char *e;
|
---|
88 | struct sigaction common_act, ill_oact, bus_oact;
|
---|
89 | sigset_t all_masked, oset;
|
---|
90 | static int trigger = 0;
|
---|
91 |
|
---|
92 | if (trigger)
|
---|
93 | return;
|
---|
94 | trigger = 1;
|
---|
95 |
|
---|
96 | if ((e = getenv("OPENSSL_sparcv9cap"))) {
|
---|
97 | OPENSSL_sparcv9cap_P[0] = strtoul(e, NULL, 0);
|
---|
98 | if ((e = strchr(e, ':')))
|
---|
99 | OPENSSL_sparcv9cap_P[1] = strtoul(e + 1, NULL, 0);
|
---|
100 | return;
|
---|
101 | }
|
---|
102 |
|
---|
103 | #if defined(__sun) && defined(__SVR4)
|
---|
104 | if (getisax != NULL) {
|
---|
105 | unsigned int vec[2] = { 0, 0 };
|
---|
106 |
|
---|
107 | if (getisax (vec,2)) {
|
---|
108 | if (vec[0]&0x00020) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1;
|
---|
109 | if (vec[0]&0x00040) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2;
|
---|
110 | if (vec[0]&0x00080) OPENSSL_sparcv9cap_P[0] |= SPARCV9_BLK;
|
---|
111 | if (vec[0]&0x00100) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD;
|
---|
112 | if (vec[0]&0x00400) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3;
|
---|
113 | if (vec[0]&0x01000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJHPCACE;
|
---|
114 | if (vec[0]&0x02000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJDESX;
|
---|
115 | if (vec[0]&0x08000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_IMA;
|
---|
116 | if (vec[0]&0x10000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJAESX;
|
---|
117 | if (vec[1]&0x00008) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS4;
|
---|
118 |
|
---|
119 | /* reconstruct %cfr copy */
|
---|
120 | OPENSSL_sparcv9cap_P[1] = (vec[0]>>17)&0x3ff;
|
---|
121 | OPENSSL_sparcv9cap_P[1] |= (OPENSSL_sparcv9cap_P[1]&CFR_MONTMUL)<<1;
|
---|
122 | if (vec[0]&0x20000000) OPENSSL_sparcv9cap_P[1] |= CFR_CRC32C;
|
---|
123 | if (vec[1]&0x00000020) OPENSSL_sparcv9cap_P[1] |= CFR_XMPMUL;
|
---|
124 | if (vec[1]&0x00000040)
|
---|
125 | OPENSSL_sparcv9cap_P[1] |= CFR_XMONTMUL|CFR_XMONTSQR;
|
---|
126 |
|
---|
127 | /* Some heuristics */
|
---|
128 | /* all known VIS2-capable CPUs have unprivileged tick counter */
|
---|
129 | if (OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS2)
|
---|
130 | OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED;
|
---|
131 |
|
---|
132 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_PREFER_FPU;
|
---|
133 |
|
---|
134 | /* detect UltraSPARC-Tx, see sparccpud.S for details... */
|
---|
135 | if ((OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS1) &&
|
---|
136 | _sparcv9_vis1_instrument() >= 12)
|
---|
137 | OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU);
|
---|
138 | }
|
---|
139 |
|
---|
140 | if (sizeof(size_t) == 8)
|
---|
141 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK;
|
---|
142 |
|
---|
143 | return;
|
---|
144 | }
|
---|
145 | #endif
|
---|
146 |
|
---|
147 | /* Initial value, fits UltraSPARC-I&II... */
|
---|
148 | OPENSSL_sparcv9cap_P[0] = SPARCV9_PREFER_FPU | SPARCV9_TICK_PRIVILEGED;
|
---|
149 |
|
---|
150 | sigfillset(&all_masked);
|
---|
151 | sigdelset(&all_masked, SIGILL);
|
---|
152 | sigdelset(&all_masked, SIGTRAP);
|
---|
153 | # ifdef SIGEMT
|
---|
154 | sigdelset(&all_masked, SIGEMT);
|
---|
155 | # endif
|
---|
156 | sigdelset(&all_masked, SIGFPE);
|
---|
157 | sigdelset(&all_masked, SIGBUS);
|
---|
158 | sigdelset(&all_masked, SIGSEGV);
|
---|
159 | sigprocmask(SIG_SETMASK, &all_masked, &oset);
|
---|
160 |
|
---|
161 | memset(&common_act, 0, sizeof(common_act));
|
---|
162 | common_act.sa_handler = common_handler;
|
---|
163 | common_act.sa_mask = all_masked;
|
---|
164 |
|
---|
165 | sigaction(SIGILL, &common_act, &ill_oact);
|
---|
166 | sigaction(SIGBUS, &common_act, &bus_oact); /* T1 fails 16-bit ldda [on
|
---|
167 | * Linux] */
|
---|
168 |
|
---|
169 | if (sigsetjmp(common_jmp, 1) == 0) {
|
---|
170 | _sparcv9_rdtick();
|
---|
171 | OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED;
|
---|
172 | }
|
---|
173 |
|
---|
174 | if (sigsetjmp(common_jmp, 1) == 0) {
|
---|
175 | _sparcv9_vis1_probe();
|
---|
176 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1 | SPARCV9_BLK;
|
---|
177 | /* detect UltraSPARC-Tx, see sparccpud.S for details... */
|
---|
178 | if (_sparcv9_vis1_instrument() >= 12)
|
---|
179 | OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU);
|
---|
180 | else {
|
---|
181 | _sparcv9_vis2_probe();
|
---|
182 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2;
|
---|
183 | }
|
---|
184 | }
|
---|
185 |
|
---|
186 | if (sigsetjmp(common_jmp, 1) == 0) {
|
---|
187 | _sparcv9_fmadd_probe();
|
---|
188 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD;
|
---|
189 | }
|
---|
190 |
|
---|
191 | /*
|
---|
192 | * VIS3 flag is tested independently from VIS1, unlike VIS2 that is,
|
---|
193 | * because VIS3 defines even integer instructions.
|
---|
194 | */
|
---|
195 | if (sigsetjmp(common_jmp, 1) == 0) {
|
---|
196 | _sparcv9_vis3_probe();
|
---|
197 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3;
|
---|
198 | }
|
---|
199 |
|
---|
200 | if (sigsetjmp(common_jmp, 1) == 0) {
|
---|
201 | _sparcv9_fjaesx_probe();
|
---|
202 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJAESX;
|
---|
203 | }
|
---|
204 |
|
---|
205 | /*
|
---|
206 | * In wait for better solution _sparcv9_rdcfr is masked by
|
---|
207 | * VIS3 flag, because it goes to uninterruptible endless
|
---|
208 | * loop on UltraSPARC II running Solaris. Things might be
|
---|
209 | * different on Linux...
|
---|
210 | */
|
---|
211 | if ((OPENSSL_sparcv9cap_P[0] & SPARCV9_VIS3) &&
|
---|
212 | sigsetjmp(common_jmp, 1) == 0) {
|
---|
213 | OPENSSL_sparcv9cap_P[1] = (unsigned int)_sparcv9_rdcfr();
|
---|
214 | }
|
---|
215 |
|
---|
216 | sigaction(SIGBUS, &bus_oact, NULL);
|
---|
217 | sigaction(SIGILL, &ill_oact, NULL);
|
---|
218 |
|
---|
219 | sigprocmask(SIG_SETMASK, &oset, NULL);
|
---|
220 |
|
---|
221 | if (sizeof(size_t) == 8)
|
---|
222 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK;
|
---|
223 | # ifdef __linux
|
---|
224 | else {
|
---|
225 | int ret = syscall(340);
|
---|
226 |
|
---|
227 | if (ret >= 0 && ret & 1)
|
---|
228 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK;
|
---|
229 | }
|
---|
230 | # endif
|
---|
231 | }
|
---|