1/* $OpenBSD: sparcv9cap.c,v 1.7 2014/06/20 21:00:46 deraadt Exp $ */ 2#include <stdio.h> 3#include <stdlib.h> 4#include <string.h> 5#include <setjmp.h> 6#include <signal.h> 7#include <sys/time.h> 8#include <openssl/bn.h> 9 10#define SPARCV9_PREFER_FPU (1<<1) 11#define SPARCV9_VIS1 (1<<2) 12#define SPARCV9_VIS2 (1<<3) /* reserved */ 13#define SPARCV9_FMADD (1<<4) /* reserved for SPARC64 V */ 14 15static int OPENSSL_sparcv9cap_P = 0; 16 17int 18bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, 19 const BN_ULONG *np, const BN_ULONG *n0, int num) 20{ 21 int bn_mul_mont_fpu(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np, const BN_ULONG *n0, int num); 22 int bn_mul_mont_int(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np, const BN_ULONG *n0, int num); 23 24 if (num >= 8 && !(num & 1) && 25 (OPENSSL_sparcv9cap_P & (SPARCV9_PREFER_FPU|SPARCV9_VIS1)) == 26 (SPARCV9_PREFER_FPU|SPARCV9_VIS1)) 27 return bn_mul_mont_fpu(rp, ap, bp, np, n0, num); 28 else 29 return bn_mul_mont_int(rp, ap, bp, np, n0, num); 30} 31 32void _sparcv9_vis1_probe(void); 33unsigned long _sparcv9_vis1_instrument(void); 34void _sparcv9_vis2_probe(void); 35void _sparcv9_fmadd_probe(void); 36 37static sigjmp_buf common_jmp; 38static void 39common_handler(int sig) 40{ 41 siglongjmp(common_jmp, sig); 42} 43 44void 45OPENSSL_cpuid_setup(void) 46{ 47 char *e; 48 struct sigaction common_act, ill_oact, bus_oact; 49 sigset_t all_masked, oset; 50 static int trigger = 0; 51 52 if (trigger) 53 return; 54 trigger = 1; 55 56 /* Initial value, fits UltraSPARC-I&II... */ 57 OPENSSL_sparcv9cap_P = SPARCV9_PREFER_FPU; 58 59 sigfillset(&all_masked); 60 sigdelset(&all_masked, SIGILL); 61 sigdelset(&all_masked, SIGTRAP); 62#ifdef SIGEMT 63 sigdelset(&all_masked, SIGEMT); 64#endif 65 sigdelset(&all_masked, SIGFPE); 66 sigdelset(&all_masked, SIGBUS); 67 sigdelset(&all_masked, SIGSEGV); 68 sigprocmask(SIG_SETMASK, &all_masked, &oset); 69 70 memset(&common_act, 0, sizeof(common_act)); 71 common_act.sa_handler = common_handler; 72 common_act.sa_mask = all_masked; 73 74 sigaction(SIGILL, &common_act, &ill_oact); 75 sigaction(SIGBUS,&common_act,&bus_oact);/* T1 fails 16-bit ldda [on Linux] */ 76 77 if (sigsetjmp(common_jmp, 1) == 0) { 78 _sparcv9_vis1_probe(); 79 OPENSSL_sparcv9cap_P |= SPARCV9_VIS1; 80 /* detect UltraSPARC-Tx, see sparccpud.S for details... */ 81 if (_sparcv9_vis1_instrument() >= 12) 82 OPENSSL_sparcv9cap_P &= ~(SPARCV9_VIS1|SPARCV9_PREFER_FPU); 83 else { 84 _sparcv9_vis2_probe(); 85 OPENSSL_sparcv9cap_P |= SPARCV9_VIS2; 86 } 87 } 88 89 if (sigsetjmp(common_jmp, 1) == 0) { 90 _sparcv9_fmadd_probe(); 91 OPENSSL_sparcv9cap_P |= SPARCV9_FMADD; 92 } 93 94 sigaction(SIGBUS, &bus_oact, NULL); 95 sigaction(SIGILL, &ill_oact, NULL); 96 97 sigprocmask(SIG_SETMASK, &oset, NULL); 98} 99