Andy Polyakov | c06b0f3 | 2005-12-15 22:50:36 +0000 | [diff] [blame] | 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
| 3 | #include <string.h> |
Andy Polyakov | c32fcca | 2010-07-01 07:34:56 +0000 | [diff] [blame] | 4 | #include <setjmp.h> |
| 5 | #include <signal.h> |
Andy Polyakov | c06b0f3 | 2005-12-15 22:50:36 +0000 | [diff] [blame] | 6 | #include <sys/time.h> |
Andy Polyakov | 68c06bf | 2012-11-17 10:34:11 +0000 | [diff] [blame] | 7 | #include <unistd.h> |
Andy Polyakov | c06b0f3 | 2005-12-15 22:50:36 +0000 | [diff] [blame] | 8 | #include <openssl/bn.h> |
| 9 | |
Andy Polyakov | 1fda639 | 2012-09-23 20:29:03 +0000 | [diff] [blame] | 10 | #include "sparc_arch.h" |
Andy Polyakov | c32fcca | 2010-07-01 07:34:56 +0000 | [diff] [blame] | 11 | |
Andy Polyakov | 1fda639 | 2012-09-23 20:29:03 +0000 | [diff] [blame] | 12 | #if defined(__GNUC__) && defined(__linux) |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 13 | __attribute__ ((visibility("hidden"))) |
Andy Polyakov | 1fda639 | 2012-09-23 20:29:03 +0000 | [diff] [blame] | 14 | #endif |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 15 | unsigned int OPENSSL_sparcv9cap_P[2] = { SPARCV9_TICK_PRIVILEGED, 0 }; |
Andy Polyakov | c06b0f3 | 2005-12-15 22:50:36 +0000 | [diff] [blame] | 16 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 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); |
Andy Polyakov | c06b0f3 | 2005-12-15 22:50:36 +0000 | [diff] [blame] | 26 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 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]; |
Andy Polyakov | 68c06bf | 2012-11-17 10:34:11 +0000 | [diff] [blame] | 52 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 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 | } |
Andy Polyakov | c06b0f3 | 2005-12-15 22:50:36 +0000 | [diff] [blame] | 70 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 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); |
Andy Polyakov | c32fcca | 2010-07-01 07:34:56 +0000 | [diff] [blame] | 81 | |
Andy Polyakov | c06b0f3 | 2005-12-15 22:50:36 +0000 | [diff] [blame] | 82 | unsigned long OPENSSL_rdtsc(void) |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 83 | { |
| 84 | if (OPENSSL_sparcv9cap_P[0] & SPARCV9_TICK_PRIVILEGED) |
Andy Polyakov | c06b0f3 | 2005-12-15 22:50:36 +0000 | [diff] [blame] | 85 | #if defined(__sun) && defined(__SVR4) |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 86 | return gethrtime(); |
Andy Polyakov | c06b0f3 | 2005-12-15 22:50:36 +0000 | [diff] [blame] | 87 | #else |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 88 | return 0; |
Andy Polyakov | c06b0f3 | 2005-12-15 22:50:36 +0000 | [diff] [blame] | 89 | #endif |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 90 | else |
| 91 | return _sparcv9_rdtick(); |
| 92 | } |
Andy Polyakov | c06b0f3 | 2005-12-15 22:50:36 +0000 | [diff] [blame] | 93 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 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 | } |
Andy Polyakov | 5fabb88 | 2011-04-17 12:46:00 +0000 | [diff] [blame] | 102 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 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 | } |
Andy Polyakov | 5fabb88 | 2011-04-17 12:46:00 +0000 | [diff] [blame] | 111 | |
Andy Polyakov | c32fcca | 2010-07-01 07:34:56 +0000 | [diff] [blame] | 112 | static sigjmp_buf common_jmp; |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 113 | static void common_handler(int sig) |
| 114 | { |
| 115 | siglongjmp(common_jmp, sig); |
| 116 | } |
Andy Polyakov | c32fcca | 2010-07-01 07:34:56 +0000 | [diff] [blame] | 117 | |
Andy Polyakov | 2238e0e | 2015-12-01 12:21:08 +0100 | [diff] [blame] | 118 | #if defined(__sun) && defined(__SVR4) |
| 119 | # if defined(__GNUC__) && __GNUC__>=2 |
| 120 | extern unsigned int getisax(unsigned int vec[], unsigned int sz) __attribute__ ((weak)); |
| 121 | # elif defined(__SUNPRO_C) |
| 122 | #pragma weak getisax |
| 123 | extern unsigned int getisax(unsigned int vec[], unsigned int sz); |
| 124 | # else |
| 125 | static unsigned int (*getisax) (unsigned int vec[], unsigned int sz) = NULL; |
| 126 | # endif |
| 127 | #endif |
| 128 | |
Andy Polyakov | 5d7324e | 2005-12-18 19:13:03 +0000 | [diff] [blame] | 129 | void OPENSSL_cpuid_setup(void) |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 130 | { |
| 131 | char *e; |
| 132 | struct sigaction common_act, ill_oact, bus_oact; |
| 133 | sigset_t all_masked, oset; |
| 134 | static int trigger = 0; |
Andy Polyakov | 4b2603e | 2010-09-05 19:41:41 +0000 | [diff] [blame] | 135 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 136 | if (trigger) |
| 137 | return; |
| 138 | trigger = 1; |
Andy Polyakov | c06b0f3 | 2005-12-15 22:50:36 +0000 | [diff] [blame] | 139 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 140 | if ((e = getenv("OPENSSL_sparcv9cap"))) { |
| 141 | OPENSSL_sparcv9cap_P[0] = strtoul(e, NULL, 0); |
| 142 | if ((e = strchr(e, ':'))) |
| 143 | OPENSSL_sparcv9cap_P[1] = strtoul(e + 1, NULL, 0); |
| 144 | return; |
| 145 | } |
Andy Polyakov | c32fcca | 2010-07-01 07:34:56 +0000 | [diff] [blame] | 146 | |
Andy Polyakov | 2238e0e | 2015-12-01 12:21:08 +0100 | [diff] [blame] | 147 | #if defined(__sun) && defined(__SVR4) |
| 148 | if (getisax != NULL) { |
| 149 | unsigned int vec[1]; |
| 150 | |
| 151 | if (getisax (vec,1)) { |
| 152 | if (vec[0]&0x0020) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1; |
| 153 | if (vec[0]&0x0040) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2; |
| 154 | if (vec[0]&0x0080) OPENSSL_sparcv9cap_P[0] |= SPARCV9_BLK; |
| 155 | if (vec[0]&0x0100) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD; |
| 156 | if (vec[0]&0x0400) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3; |
| 157 | |
| 158 | /* reconstruct %cfr copy */ |
| 159 | OPENSSL_sparcv9cap_P[1] = (vec[0]>>17)&0x3ff; |
| 160 | OPENSSL_sparcv9cap_P[1] |= (OPENSSL_sparcv9cap_P[1]&CFR_MONTMUL)<<1; |
| 161 | if (vec[0]&0x20000000) OPENSSL_sparcv9cap_P[1] |= CFR_CRC32C; |
| 162 | |
| 163 | /* Some heuristics */ |
| 164 | /* all known VIS2-capable CPUs have unprivileged tick counter */ |
| 165 | if (OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS2) |
| 166 | OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED; |
| 167 | |
| 168 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_PREFER_FPU; |
| 169 | |
| 170 | /* detect UltraSPARC-Tx, see sparccpud.S for details... */ |
| 171 | if ((OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS1) && |
| 172 | _sparcv9_vis1_instrument() >= 12) |
| 173 | OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU); |
| 174 | } |
| 175 | |
| 176 | if (sizeof(size_t) == 8) |
| 177 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK; |
| 178 | |
| 179 | return; |
| 180 | } |
| 181 | #endif |
| 182 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 183 | /* Initial value, fits UltraSPARC-I&II... */ |
| 184 | OPENSSL_sparcv9cap_P[0] = SPARCV9_PREFER_FPU | SPARCV9_TICK_PRIVILEGED; |
Andy Polyakov | c32fcca | 2010-07-01 07:34:56 +0000 | [diff] [blame] | 185 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 186 | sigfillset(&all_masked); |
| 187 | sigdelset(&all_masked, SIGILL); |
| 188 | sigdelset(&all_masked, SIGTRAP); |
| 189 | # ifdef SIGEMT |
| 190 | sigdelset(&all_masked, SIGEMT); |
| 191 | # endif |
| 192 | sigdelset(&all_masked, SIGFPE); |
| 193 | sigdelset(&all_masked, SIGBUS); |
| 194 | sigdelset(&all_masked, SIGSEGV); |
| 195 | sigprocmask(SIG_SETMASK, &all_masked, &oset); |
Andy Polyakov | c32fcca | 2010-07-01 07:34:56 +0000 | [diff] [blame] | 196 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 197 | memset(&common_act, 0, sizeof(common_act)); |
| 198 | common_act.sa_handler = common_handler; |
| 199 | common_act.sa_mask = all_masked; |
Andy Polyakov | 4b2603e | 2010-09-05 19:41:41 +0000 | [diff] [blame] | 200 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 201 | sigaction(SIGILL, &common_act, &ill_oact); |
| 202 | sigaction(SIGBUS, &common_act, &bus_oact); /* T1 fails 16-bit ldda [on |
| 203 | * Linux] */ |
Andy Polyakov | c32fcca | 2010-07-01 07:34:56 +0000 | [diff] [blame] | 204 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 205 | if (sigsetjmp(common_jmp, 1) == 0) { |
| 206 | _sparcv9_rdtick(); |
| 207 | OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED; |
| 208 | } |
Andy Polyakov | 4b2603e | 2010-09-05 19:41:41 +0000 | [diff] [blame] | 209 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 210 | if (sigsetjmp(common_jmp, 1) == 0) { |
| 211 | _sparcv9_vis1_probe(); |
| 212 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1 | SPARCV9_BLK; |
| 213 | /* detect UltraSPARC-Tx, see sparccpud.S for details... */ |
| 214 | if (_sparcv9_vis1_instrument() >= 12) |
| 215 | OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU); |
| 216 | else { |
| 217 | _sparcv9_vis2_probe(); |
| 218 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2; |
| 219 | } |
| 220 | } |
Andy Polyakov | 1fda639 | 2012-09-23 20:29:03 +0000 | [diff] [blame] | 221 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 222 | if (sigsetjmp(common_jmp, 1) == 0) { |
| 223 | _sparcv9_fmadd_probe(); |
| 224 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD; |
| 225 | } |
Andy Polyakov | 1fda639 | 2012-09-23 20:29:03 +0000 | [diff] [blame] | 226 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 227 | /* |
| 228 | * VIS3 flag is tested independently from VIS1, unlike VIS2 that is, |
| 229 | * because VIS3 defines even integer instructions. |
| 230 | */ |
| 231 | if (sigsetjmp(common_jmp, 1) == 0) { |
| 232 | _sparcv9_vis3_probe(); |
| 233 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3; |
| 234 | } |
Andy Polyakov | 1fda639 | 2012-09-23 20:29:03 +0000 | [diff] [blame] | 235 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 236 | /* |
| 237 | * In wait for better solution _sparcv9_rdcfr is masked by |
| 238 | * VIS3 flag, because it goes to uninterruptable endless |
| 239 | * loop on UltraSPARC II running Solaris. Things might be |
| 240 | * different on Linux... |
| 241 | */ |
| 242 | if ((OPENSSL_sparcv9cap_P[0] & SPARCV9_VIS3) && |
| 243 | sigsetjmp(common_jmp, 1) == 0) { |
| 244 | OPENSSL_sparcv9cap_P[1] = (unsigned int)_sparcv9_rdcfr(); |
| 245 | } |
Andy Polyakov | 4b2603e | 2010-09-05 19:41:41 +0000 | [diff] [blame] | 246 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 247 | sigaction(SIGBUS, &bus_oact, NULL); |
| 248 | sigaction(SIGILL, &ill_oact, NULL); |
Andy Polyakov | 7c5889b | 2010-07-08 07:47:35 +0000 | [diff] [blame] | 249 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 250 | sigprocmask(SIG_SETMASK, &oset, NULL); |
Andy Polyakov | 68c06bf | 2012-11-17 10:34:11 +0000 | [diff] [blame] | 251 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 252 | if (sizeof(size_t) == 8) |
| 253 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK; |
| 254 | # ifdef __linux |
| 255 | else { |
| 256 | int ret = syscall(340); |
Andy Polyakov | 68c06bf | 2012-11-17 10:34:11 +0000 | [diff] [blame] | 257 | |
Matt Caswell | 0f113f3 | 2015-01-22 03:40:55 +0000 | [diff] [blame] | 258 | if (ret >= 0 && ret & 1) |
| 259 | OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK; |
| 260 | } |
| 261 | # endif |
| 262 | } |