113ce5681Schristos #include <stdio.h>
213ce5681Schristos #include <stdlib.h>
313ce5681Schristos #include <string.h>
413ce5681Schristos #include <setjmp.h>
513ce5681Schristos #include <signal.h>
6*21bfa713Schristos #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
1813ce5681Schristos int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np, const BN_ULONG *n0, int num)
1913ce5681Schristos 	{
2013ce5681Schristos 	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);
2113ce5681Schristos 	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);
2213ce5681Schristos 
2313ce5681Schristos 	if (sizeof(size_t)==4)
2413ce5681Schristos 		{
2513ce5681Schristos #if (defined(__APPLE__) && defined(__MACH__))
2613ce5681Schristos 		if (num>=8 && (num&3)==0 && (OPENSSL_ppccap_P&PPC_FPU64))
2713ce5681Schristos 			return bn_mul_mont_fpu64(rp,ap,bp,np,n0,num);
2813ce5681Schristos #else
2913ce5681Schristos 		/* boundary of 32 was experimentally determined on
3013ce5681Schristos 		   Linux 2.6.22, might have to be adjusted on AIX... */
3113ce5681Schristos 		if (num>=32 && (num&3)==0 && (OPENSSL_ppccap_P&PPC_FPU64))
3213ce5681Schristos 			{
3313ce5681Schristos 			sigset_t oset;
3413ce5681Schristos 			int ret;
3513ce5681Schristos 
3613ce5681Schristos 			sigprocmask(SIG_SETMASK,&all_masked,&oset);
3713ce5681Schristos 			ret=bn_mul_mont_fpu64(rp,ap,bp,np,n0,num);
3813ce5681Schristos 			sigprocmask(SIG_SETMASK,&oset,NULL);
3913ce5681Schristos 
4013ce5681Schristos 			return ret;
4113ce5681Schristos 			}
4213ce5681Schristos #endif
4313ce5681Schristos 		}
4413ce5681Schristos 	else if ((OPENSSL_ppccap_P&PPC_FPU64))
4513ce5681Schristos 		/* this is a "must" on POWER6, but run-time detection
4613ce5681Schristos 		 * is not implemented yet... */
4713ce5681Schristos 		return bn_mul_mont_fpu64(rp,ap,bp,np,n0,num);
4813ce5681Schristos 
4913ce5681Schristos 	return bn_mul_mont_int(rp,ap,bp,np,n0,num);
5013ce5681Schristos 	}
5113ce5681Schristos #endif
5213ce5681Schristos 
5313ce5681Schristos static sigjmp_buf ill_jmp;
5413ce5681Schristos static void ill_handler (int sig) { siglongjmp(ill_jmp,sig); }
5513ce5681Schristos 
5613ce5681Schristos void OPENSSL_ppc64_probe(void);
57*21bfa713Schristos void OPENSSL_altivec_probe(void);
5813ce5681Schristos 
5913ce5681Schristos void OPENSSL_cpuid_setup(void)
6013ce5681Schristos 	{
6113ce5681Schristos 	char *e;
6213ce5681Schristos 	struct sigaction	ill_oact,ill_act;
6313ce5681Schristos 	sigset_t		oset;
6413ce5681Schristos 	static int trigger=0;
6513ce5681Schristos 
6613ce5681Schristos 	if (trigger) return;
6713ce5681Schristos 	trigger=1;
6813ce5681Schristos 
6913ce5681Schristos 	sigfillset(&all_masked);
7013ce5681Schristos 	sigdelset(&all_masked,SIGILL);
7113ce5681Schristos 	sigdelset(&all_masked,SIGTRAP);
7213ce5681Schristos #ifdef SIGEMT
7313ce5681Schristos 	sigdelset(&all_masked,SIGEMT);
7413ce5681Schristos #endif
7513ce5681Schristos 	sigdelset(&all_masked,SIGFPE);
7613ce5681Schristos 	sigdelset(&all_masked,SIGBUS);
7713ce5681Schristos 	sigdelset(&all_masked,SIGSEGV);
7813ce5681Schristos 
791e7e732cSmatt 	if ((e=getenv("OPENSSL_ppccap")) != NULL)
8013ce5681Schristos 		{
8113ce5681Schristos 		OPENSSL_ppccap_P=strtoul(e,NULL,0);
8213ce5681Schristos 		return;
8313ce5681Schristos 		}
8413ce5681Schristos 
8513ce5681Schristos 	OPENSSL_ppccap_P = 0;
8613ce5681Schristos 
87*21bfa713Schristos #if defined(_AIX)
88*21bfa713Schristos 	if (sizeof(size_t)==4
89*21bfa713Schristos # if defined(_SC_AIX_KERNEL_BITMODE)
90*21bfa713Schristos 	    && sysconf(_SC_AIX_KERNEL_BITMODE)!=64
91*21bfa713Schristos # endif
92*21bfa713Schristos 	   )
93*21bfa713Schristos 		return;
94*21bfa713Schristos #endif
95*21bfa713Schristos 
9613ce5681Schristos 	memset(&ill_act,0,sizeof(ill_act));
9713ce5681Schristos 	ill_act.sa_handler = ill_handler;
9813ce5681Schristos 	ill_act.sa_mask    = all_masked;
9913ce5681Schristos 
10013ce5681Schristos 	sigprocmask(SIG_SETMASK,&ill_act.sa_mask,&oset);
10113ce5681Schristos 	sigaction(SIGILL,&ill_act,&ill_oact);
10213ce5681Schristos 
10313ce5681Schristos 	if (sizeof(size_t)==4)
10413ce5681Schristos 		{
10513ce5681Schristos 		if (sigsetjmp(ill_jmp,1) == 0)
10613ce5681Schristos 			{
10713ce5681Schristos 			OPENSSL_ppc64_probe();
10813ce5681Schristos 			OPENSSL_ppccap_P |= PPC_FPU64;
10913ce5681Schristos 			}
11013ce5681Schristos 		}
11113ce5681Schristos 	else
11213ce5681Schristos 		{
11313ce5681Schristos 		/*
11413ce5681Schristos 		 * Wanted code detecting POWER6 CPU and setting PPC_FPU64
11513ce5681Schristos 		 */
11613ce5681Schristos 		}
11713ce5681Schristos 
11813ce5681Schristos 	if (sigsetjmp(ill_jmp,1) == 0)
11913ce5681Schristos 		{
1201e7e732cSmatt 		void OPENSSL_altivec_probe();
12113ce5681Schristos 		OPENSSL_altivec_probe();
12213ce5681Schristos 		OPENSSL_ppccap_P |= PPC_ALTIVEC;
12313ce5681Schristos 		}
12413ce5681Schristos 
12513ce5681Schristos 	sigaction (SIGILL,&ill_oact,NULL);
12613ce5681Schristos 	sigprocmask(SIG_SETMASK,&oset,NULL);
12713ce5681Schristos 	}
128