1238384Sjkim#include <stdio.h> 2238384Sjkim#include <stdlib.h> 3238384Sjkim#include <string.h> 4238384Sjkim#include <setjmp.h> 5238384Sjkim#include <signal.h> 6246772Sjkim#include <unistd.h> 7238384Sjkim#include <crypto.h> 8238384Sjkim#include <openssl/bn.h> 9238384Sjkim 10238384Sjkim#define PPC_FPU64 (1<<0) 11238384Sjkim#define PPC_ALTIVEC (1<<1) 12238384Sjkim 13238384Sjkimstatic int OPENSSL_ppccap_P = 0; 14238384Sjkim 15238384Sjkimstatic sigset_t all_masked; 16238384Sjkim 17238384Sjkim#ifdef OPENSSL_BN_ASM_MONT 18238384Sjkimint bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np, const BN_ULONG *n0, int num) 19238384Sjkim { 20238384Sjkim int bn_mul_mont_fpu64(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np, const BN_ULONG *n0, int num); 21238384Sjkim 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); 22238384Sjkim 23238384Sjkim if (sizeof(size_t)==4) 24238384Sjkim { 25238384Sjkim#if (defined(__APPLE__) && defined(__MACH__)) 26238384Sjkim if (num>=8 && (num&3)==0 && (OPENSSL_ppccap_P&PPC_FPU64)) 27238384Sjkim return bn_mul_mont_fpu64(rp,ap,bp,np,n0,num); 28238384Sjkim#else 29238384Sjkim /* boundary of 32 was experimentally determined on 30238384Sjkim Linux 2.6.22, might have to be adjusted on AIX... */ 31238384Sjkim if (num>=32 && (num&3)==0 && (OPENSSL_ppccap_P&PPC_FPU64)) 32238384Sjkim { 33238384Sjkim sigset_t oset; 34238384Sjkim int ret; 35238384Sjkim 36238384Sjkim sigprocmask(SIG_SETMASK,&all_masked,&oset); 37238384Sjkim ret=bn_mul_mont_fpu64(rp,ap,bp,np,n0,num); 38238384Sjkim sigprocmask(SIG_SETMASK,&oset,NULL); 39238384Sjkim 40238384Sjkim return ret; 41238384Sjkim } 42238384Sjkim#endif 43238384Sjkim } 44238384Sjkim else if ((OPENSSL_ppccap_P&PPC_FPU64)) 45238384Sjkim /* this is a "must" on POWER6, but run-time detection 46238384Sjkim * is not implemented yet... */ 47238384Sjkim return bn_mul_mont_fpu64(rp,ap,bp,np,n0,num); 48238384Sjkim 49238384Sjkim return bn_mul_mont_int(rp,ap,bp,np,n0,num); 50238384Sjkim } 51238384Sjkim#endif 52238384Sjkim 53238384Sjkimstatic sigjmp_buf ill_jmp; 54238384Sjkimstatic void ill_handler (int sig) { siglongjmp(ill_jmp,sig); } 55238384Sjkim 56238384Sjkimvoid OPENSSL_ppc64_probe(void); 57246772Sjkimvoid OPENSSL_altivec_probe(void); 58238384Sjkim 59238384Sjkimvoid OPENSSL_cpuid_setup(void) 60238384Sjkim { 61238384Sjkim char *e; 62238384Sjkim struct sigaction ill_oact,ill_act; 63238384Sjkim sigset_t oset; 64238384Sjkim static int trigger=0; 65238384Sjkim 66238384Sjkim if (trigger) return; 67238384Sjkim trigger=1; 68238384Sjkim 69238384Sjkim sigfillset(&all_masked); 70238384Sjkim sigdelset(&all_masked,SIGILL); 71238384Sjkim sigdelset(&all_masked,SIGTRAP); 72238384Sjkim#ifdef SIGEMT 73238384Sjkim sigdelset(&all_masked,SIGEMT); 74238384Sjkim#endif 75238384Sjkim sigdelset(&all_masked,SIGFPE); 76238384Sjkim sigdelset(&all_masked,SIGBUS); 77238384Sjkim sigdelset(&all_masked,SIGSEGV); 78238384Sjkim 79238384Sjkim if ((e=getenv("OPENSSL_ppccap"))) 80238384Sjkim { 81238384Sjkim OPENSSL_ppccap_P=strtoul(e,NULL,0); 82238384Sjkim return; 83238384Sjkim } 84238384Sjkim 85238384Sjkim OPENSSL_ppccap_P = 0; 86238384Sjkim 87246772Sjkim#if defined(_AIX) 88246772Sjkim if (sizeof(size_t)==4 89246772Sjkim# if defined(_SC_AIX_KERNEL_BITMODE) 90246772Sjkim && sysconf(_SC_AIX_KERNEL_BITMODE)!=64 91246772Sjkim# endif 92246772Sjkim ) 93246772Sjkim return; 94246772Sjkim#endif 95246772Sjkim 96238384Sjkim memset(&ill_act,0,sizeof(ill_act)); 97238384Sjkim ill_act.sa_handler = ill_handler; 98238384Sjkim ill_act.sa_mask = all_masked; 99238384Sjkim 100238384Sjkim sigprocmask(SIG_SETMASK,&ill_act.sa_mask,&oset); 101238384Sjkim sigaction(SIGILL,&ill_act,&ill_oact); 102238384Sjkim 103238384Sjkim if (sizeof(size_t)==4) 104238384Sjkim { 105238384Sjkim if (sigsetjmp(ill_jmp,1) == 0) 106238384Sjkim { 107238384Sjkim OPENSSL_ppc64_probe(); 108238384Sjkim OPENSSL_ppccap_P |= PPC_FPU64; 109238384Sjkim } 110238384Sjkim } 111238384Sjkim else 112238384Sjkim { 113238384Sjkim /* 114238384Sjkim * Wanted code detecting POWER6 CPU and setting PPC_FPU64 115238384Sjkim */ 116238384Sjkim } 117238384Sjkim 118238384Sjkim if (sigsetjmp(ill_jmp,1) == 0) 119238384Sjkim { 120238384Sjkim OPENSSL_altivec_probe(); 121238384Sjkim OPENSSL_ppccap_P |= PPC_ALTIVEC; 122238384Sjkim } 123238384Sjkim 124238384Sjkim sigaction (SIGILL,&ill_oact,NULL); 125238384Sjkim sigprocmask(SIG_SETMASK,&oset,NULL); 126238384Sjkim } 127