Return smaller of ret and f.
[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 void sha256_block_p8(void *ctx,const void *inp,size_t len);
58 void sha256_block_ppc(void *ctx,const void *inp,size_t len);
59 void sha256_block_data_order(void *ctx,const void *inp,size_t len)
60         {
61         OPENSSL_ppccap_P&PPC_CRYPTO207? sha256_block_p8(ctx,inp,len):
62                                         sha256_block_ppc(ctx,inp,len);
63         }
64
65 void sha512_block_p8(void *ctx,const void *inp,size_t len);
66 void sha512_block_ppc(void *ctx,const void *inp,size_t len);
67 void sha512_block_data_order(void *ctx,const void *inp,size_t len)
68         {
69         OPENSSL_ppccap_P&PPC_CRYPTO207? sha512_block_p8(ctx,inp,len):
70                                         sha512_block_ppc(ctx,inp,len);
71         }
72
73 static sigjmp_buf ill_jmp;
74 static void ill_handler (int sig) { siglongjmp(ill_jmp,sig); }
75
76 void OPENSSL_ppc64_probe(void);
77 void OPENSSL_altivec_probe(void);
78 void OPENSSL_crypto207_probe(void);
79
80 void OPENSSL_cpuid_setup(void)
81         {
82         char *e;
83         struct sigaction        ill_oact,ill_act;
84         sigset_t                oset;
85         static int trigger=0;
86
87         if (trigger) return;
88         trigger=1;
89  
90         sigfillset(&all_masked);
91         sigdelset(&all_masked,SIGILL);
92         sigdelset(&all_masked,SIGTRAP);
93 #ifdef SIGEMT
94         sigdelset(&all_masked,SIGEMT);
95 #endif
96         sigdelset(&all_masked,SIGFPE);
97         sigdelset(&all_masked,SIGBUS);
98         sigdelset(&all_masked,SIGSEGV);
99
100         if ((e=getenv("OPENSSL_ppccap")))
101                 {
102                 OPENSSL_ppccap_P=strtoul(e,NULL,0);
103                 return;
104                 }
105
106         OPENSSL_ppccap_P = 0;
107
108 #if defined(_AIX)
109         if (sizeof(size_t)==4)
110                 {
111                 struct utsname uts;
112 # if defined(_SC_AIX_KERNEL_BITMODE)
113                 if (sysconf(_SC_AIX_KERNEL_BITMODE)!=64)        return;
114 # endif
115                 if (uname(&uts)!=0 || atoi(uts.version)<6)      return;
116                 }
117 #endif
118
119         memset(&ill_act,0,sizeof(ill_act));
120         ill_act.sa_handler = ill_handler;
121         ill_act.sa_mask    = all_masked;
122
123         sigprocmask(SIG_SETMASK,&ill_act.sa_mask,&oset);
124         sigaction(SIGILL,&ill_act,&ill_oact);
125
126         if (sizeof(size_t)==4)
127                 {
128 #ifdef __linux
129                 struct utsname uts;
130                 if (uname(&uts)==0 && strcmp(uts.machine,"ppc64")==0)
131 #endif
132                 if (sigsetjmp(ill_jmp,1) == 0)
133                         {
134                         OPENSSL_ppc64_probe();
135                         OPENSSL_ppccap_P |= PPC_FPU64;
136                         }
137                 }
138         else
139                 {
140                 /*
141                  * Wanted code detecting POWER6 CPU and setting PPC_FPU64
142                  */
143                 }
144
145         if (sigsetjmp(ill_jmp,1) == 0)
146                 {
147                 OPENSSL_altivec_probe();
148                 OPENSSL_ppccap_P |= PPC_ALTIVEC;
149                 if (sigsetjmp(ill_jmp,1) == 0)
150                         {
151                         OPENSSL_crypto207_probe();
152                         OPENSSL_ppccap_P |= PPC_CRYPTO207;
153                         }
154                 }
155
156         sigaction (SIGILL,&ill_oact,NULL);
157         sigprocmask(SIG_SETMASK,&oset,NULL);
158         }