113ce5681Schristos #include <stdio.h> 213ce5681Schristos #include <stdlib.h> 313ce5681Schristos #include <string.h> 413ce5681Schristos #include <setjmp.h> 513ce5681Schristos #include <signal.h> 621bfa713Schristos #include <unistd.h> 713ce5681Schristos #include <crypto.h> 813ce5681Schristos #include <openssl/bn.h> 913ce5681Schristos 1013ce5681Schristos #define PPC_FPU64 (1<<0) 1113ce5681Schristos #define PPC_ALTIVEC (1<<1) 1213ce5681Schristos 1313ce5681Schristos static int OPENSSL_ppccap_P = 0; 1413ce5681Schristos 1513ce5681Schristos static sigset_t all_masked; 1613ce5681Schristos 1713ce5681Schristos #ifdef OPENSSL_BN_ASM_MONT 18*d572d25fSspz int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, 19*d572d25fSspz const BN_ULONG *np, const BN_ULONG *n0, int num) 2013ce5681Schristos { 21*d572d25fSspz int bn_mul_mont_fpu64(BN_ULONG *rp, const BN_ULONG *ap, 22*d572d25fSspz const BN_ULONG *bp, const BN_ULONG *np, 23*d572d25fSspz const BN_ULONG *n0, int num); 24*d572d25fSspz int bn_mul_mont_int(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, 25*d572d25fSspz const BN_ULONG *np, const BN_ULONG *n0, int num); 2613ce5681Schristos 27*d572d25fSspz if (sizeof(size_t) == 4) { 2813ce5681Schristos # if (defined(__APPLE__) && defined(__MACH__)) 2913ce5681Schristos if (num >= 8 && (num & 3) == 0 && (OPENSSL_ppccap_P & PPC_FPU64)) 3013ce5681Schristos return bn_mul_mont_fpu64(rp, ap, bp, np, n0, num); 3113ce5681Schristos # else 32*d572d25fSspz /* 33*d572d25fSspz * boundary of 32 was experimentally determined on Linux 2.6.22, 34*d572d25fSspz * might have to be adjusted on AIX... 35*d572d25fSspz */ 36*d572d25fSspz if (num >= 32 && (num & 3) == 0 && (OPENSSL_ppccap_P & PPC_FPU64)) { 3713ce5681Schristos sigset_t oset; 3813ce5681Schristos int ret; 3913ce5681Schristos 4013ce5681Schristos sigprocmask(SIG_SETMASK, &all_masked, &oset); 4113ce5681Schristos ret = bn_mul_mont_fpu64(rp, ap, bp, np, n0, num); 4213ce5681Schristos sigprocmask(SIG_SETMASK, &oset, NULL); 4313ce5681Schristos 4413ce5681Schristos return ret; 4513ce5681Schristos } 4613ce5681Schristos # endif 47*d572d25fSspz } else if ((OPENSSL_ppccap_P & PPC_FPU64)) 48*d572d25fSspz /* 49*d572d25fSspz * this is a "must" on POWER6, but run-time detection is not 50*d572d25fSspz * implemented yet... 51*d572d25fSspz */ 5213ce5681Schristos return bn_mul_mont_fpu64(rp, ap, bp, np, n0, num); 5313ce5681Schristos 5413ce5681Schristos return bn_mul_mont_int(rp, ap, bp, np, n0, num); 5513ce5681Schristos } 5613ce5681Schristos #endif 5713ce5681Schristos 5813ce5681Schristos static sigjmp_buf ill_jmp; 59*d572d25fSspz static void ill_handler(int sig) 60*d572d25fSspz { 61*d572d25fSspz siglongjmp(ill_jmp, sig); 62*d572d25fSspz } 6313ce5681Schristos 6413ce5681Schristos void OPENSSL_ppc64_probe(void); 6521bfa713Schristos void OPENSSL_altivec_probe(void); 6613ce5681Schristos 6713ce5681Schristos void OPENSSL_cpuid_setup(void) 6813ce5681Schristos { 6913ce5681Schristos char *e; 7013ce5681Schristos struct sigaction ill_oact, ill_act; 7113ce5681Schristos sigset_t oset; 7213ce5681Schristos static int trigger = 0; 7313ce5681Schristos 74*d572d25fSspz if (trigger) 75*d572d25fSspz return; 7613ce5681Schristos trigger = 1; 7713ce5681Schristos 7813ce5681Schristos sigfillset(&all_masked); 7913ce5681Schristos sigdelset(&all_masked, SIGILL); 8013ce5681Schristos sigdelset(&all_masked, SIGTRAP); 8113ce5681Schristos #ifdef SIGEMT 8213ce5681Schristos sigdelset(&all_masked, SIGEMT); 8313ce5681Schristos #endif 8413ce5681Schristos sigdelset(&all_masked, SIGFPE); 8513ce5681Schristos sigdelset(&all_masked, SIGBUS); 8613ce5681Schristos sigdelset(&all_masked, SIGSEGV); 8713ce5681Schristos 88*d572d25fSspz if ((e = getenv("OPENSSL_ppccap"))) { 8913ce5681Schristos OPENSSL_ppccap_P = strtoul(e, NULL, 0); 9013ce5681Schristos return; 9113ce5681Schristos } 9213ce5681Schristos 9313ce5681Schristos OPENSSL_ppccap_P = 0; 9413ce5681Schristos 9521bfa713Schristos #if defined(_AIX) 9621bfa713Schristos if (sizeof(size_t) == 4 9721bfa713Schristos # if defined(_SC_AIX_KERNEL_BITMODE) 9821bfa713Schristos && sysconf(_SC_AIX_KERNEL_BITMODE) != 64 9921bfa713Schristos # endif 10021bfa713Schristos ) 10121bfa713Schristos return; 10221bfa713Schristos #endif 10321bfa713Schristos 10413ce5681Schristos memset(&ill_act, 0, sizeof(ill_act)); 10513ce5681Schristos ill_act.sa_handler = ill_handler; 10613ce5681Schristos ill_act.sa_mask = all_masked; 10713ce5681Schristos 10813ce5681Schristos sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset); 10913ce5681Schristos sigaction(SIGILL, &ill_act, &ill_oact); 11013ce5681Schristos 111*d572d25fSspz if (sizeof(size_t) == 4) { 112*d572d25fSspz if (sigsetjmp(ill_jmp, 1) == 0) { 11313ce5681Schristos OPENSSL_ppc64_probe(); 11413ce5681Schristos OPENSSL_ppccap_P |= PPC_FPU64; 11513ce5681Schristos } 116*d572d25fSspz } else { 11713ce5681Schristos /* 11813ce5681Schristos * Wanted code detecting POWER6 CPU and setting PPC_FPU64 11913ce5681Schristos */ 12013ce5681Schristos } 12113ce5681Schristos 122*d572d25fSspz if (sigsetjmp(ill_jmp, 1) == 0) { 12313ce5681Schristos OPENSSL_altivec_probe(); 12413ce5681Schristos OPENSSL_ppccap_P |= PPC_ALTIVEC; 12513ce5681Schristos } 12613ce5681Schristos 12713ce5681Schristos sigaction(SIGILL, &ill_oact, NULL); 12813ce5681Schristos sigprocmask(SIG_SETMASK, &oset, NULL); 12913ce5681Schristos } 130