4c5e88d3a0c830b2da1bc9ffb616e4c16e223f8e
[openssl.git] / crypto / ppccap.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <setjmp.h>
5 #include <signal.h>
6 #include <unistd.h>
7 #if defined(__linux) || defined(_AIX)
8 #include <sys/utsname.h>
9 #endif
10 #include <crypto.h>
11 #include <openssl/bn.h>
12
13 #define PPC_FPU64       (1<<0)
14 #define PPC_ALTIVEC     (1<<1)
15 #define PPC_CRYPTO207   (1<<2)
16
17 unsigned int OPENSSL_ppccap_P = 0;
18
19 static sigset_t all_masked;
20
21 #ifdef OPENSSL_BN_ASM_MONT
22 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)
23         {
24         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);
25         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);
26
27         if (sizeof(size_t)==4)
28                 {
29 #if 1 || (defined(__APPLE__) && defined(__MACH__))
30                 if (num>=8 && (num&3)==0 && (OPENSSL_ppccap_P&PPC_FPU64))
31                         return bn_mul_mont_fpu64(rp,ap,bp,np,n0,num);
32 #else
33                 /* boundary of 32 was experimentally determined on
34                    Linux 2.6.22, might have to be adjusted on AIX... */
35                 if (num>=32 && (num&3)==0 && (OPENSSL_ppccap_P&PPC_FPU64))
36                         {
37                         sigset_t oset;
38                         int ret;
39
40                         sigprocmask(SIG_SETMASK,&all_masked,&oset);
41                         ret=bn_mul_mont_fpu64(rp,ap,bp,np,n0,num);
42                         sigprocmask(SIG_SETMASK,&oset,NULL);
43
44                         return ret;
45                         }
46 #endif
47                 }
48         else if ((OPENSSL_ppccap_P&PPC_FPU64))
49                 /* this is a "must" on POWER6, but run-time detection
50                  * is not implemented yet... */
51                 return bn_mul_mont_fpu64(rp,ap,bp,np,n0,num);
52
53         return bn_mul_mont_int(rp,ap,bp,np,n0,num);
54         }
55 #endif
56
57 static sigjmp_buf ill_jmp;
58 static void ill_handler (int sig) { siglongjmp(ill_jmp,sig); }
59
60 void OPENSSL_ppc64_probe(void);
61 void OPENSSL_altivec_probe(void);
62 void OPENSSL_crypto207_probe(void);
63
64 void OPENSSL_cpuid_setup(void)
65         {
66         char *e;
67         struct sigaction        ill_oact,ill_act;
68         sigset_t                oset;
69         static int trigger=0;
70
71         if (trigger) return;
72         trigger=1;
73  
74         sigfillset(&all_masked);
75         sigdelset(&all_masked,SIGILL);
76         sigdelset(&all_masked,SIGTRAP);
77 #ifdef SIGEMT
78         sigdelset(&all_masked,SIGEMT);
79 #endif
80         sigdelset(&all_masked,SIGFPE);
81         sigdelset(&all_masked,SIGBUS);
82         sigdelset(&all_masked,SIGSEGV);
83
84         if ((e=getenv("OPENSSL_ppccap")))
85                 {
86                 OPENSSL_ppccap_P=strtoul(e,NULL,0);
87                 return;
88                 }
89
90         OPENSSL_ppccap_P = 0;
91
92 #if defined(_AIX)
93         if (sizeof(size_t)==4)
94                 {
95                 struct utsname uts;
96 # if defined(_SC_AIX_KERNEL_BITMODE)
97                 if (sysconf(_SC_AIX_KERNEL_BITMODE)!=64)        return;
98 # endif
99                 if (uname(&uts)!=0 || atoi(uts.version)<6)      return;
100                 }
101 #endif
102
103         memset(&ill_act,0,sizeof(ill_act));
104         ill_act.sa_handler = ill_handler;
105         ill_act.sa_mask    = all_masked;
106
107         sigprocmask(SIG_SETMASK,&ill_act.sa_mask,&oset);
108         sigaction(SIGILL,&ill_act,&ill_oact);
109
110         if (sizeof(size_t)==4)
111                 {
112 #ifdef __linux
113                 struct utsname uts;
114                 if (uname(&uts)==0 && strcmp(uts.machine,"ppc64")==0)
115 #endif
116                 if (sigsetjmp(ill_jmp,1) == 0)
117                         {
118                         OPENSSL_ppc64_probe();
119                         OPENSSL_ppccap_P |= PPC_FPU64;
120                         }
121                 }
122         else
123                 {
124                 /*
125                  * Wanted code detecting POWER6 CPU and setting PPC_FPU64
126                  */
127                 }
128
129         if (sigsetjmp(ill_jmp,1) == 0)
130                 {
131                 OPENSSL_altivec_probe();
132                 OPENSSL_ppccap_P |= PPC_ALTIVEC;
133                 if (sigsetjmp(ill_jmp,1) == 0)
134                         {
135                         OPENSSL_crypto207_probe();
136                         OPENSSL_ppccap_P |= PPC_CRYPTO207;
137                         }
138                 }
139
140         sigaction (SIGILL,&ill_oact,NULL);
141         sigprocmask(SIG_SETMASK,&oset,NULL);
142         }