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