Harden ASN.1 BIO handling of large amounts of data.
[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 #include <crypto.h>
8 #include <openssl/bn.h>
9
10 #define PPC_FPU64       (1<<0)
11 #define PPC_ALTIVEC     (1<<1)
12
13 static int OPENSSL_ppccap_P = 0;
14
15 static sigset_t all_masked;
16
17 #ifdef OPENSSL_BN_ASM_MONT
18 int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
19                 const BN_ULONG *np, const BN_ULONG *n0, int num)
20 {
21     int bn_mul_mont_fpu64(BN_ULONG *rp, const BN_ULONG *ap,
22                           const BN_ULONG *bp, const BN_ULONG *np,
23                           const BN_ULONG *n0, int num);
24     int bn_mul_mont_int(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
25                         const BN_ULONG *np, const BN_ULONG *n0, int num);
26
27     if (sizeof(size_t) == 4) {
28 # if (defined(__APPLE__) && defined(__MACH__))
29         if (num >= 8 && (num & 3) == 0 && (OPENSSL_ppccap_P & PPC_FPU64))
30             return bn_mul_mont_fpu64(rp, ap, bp, np, n0, num);
31 # else
32         /*
33          * boundary of 32 was experimentally determined on Linux 2.6.22,
34          * might have to be adjusted on AIX...
35          */
36         if (num >= 32 && (num & 3) == 0 && (OPENSSL_ppccap_P & PPC_FPU64)) {
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     } else if ((OPENSSL_ppccap_P & PPC_FPU64))
48         /*
49          * this is a "must" on POWER6, but run-time detection is not
50          * implemented yet...
51          */
52         return bn_mul_mont_fpu64(rp, ap, bp, np, n0, num);
53
54     return bn_mul_mont_int(rp, ap, bp, np, n0, num);
55 }
56 #endif
57
58 static sigjmp_buf ill_jmp;
59 static void ill_handler(int sig)
60 {
61     siglongjmp(ill_jmp, sig);
62 }
63
64 void OPENSSL_ppc64_probe(void);
65 void OPENSSL_altivec_probe(void);
66
67 void OPENSSL_cpuid_setup(void)
68 {
69     char *e;
70     struct sigaction ill_oact, ill_act;
71     sigset_t oset;
72     static int trigger = 0;
73
74     if (trigger)
75         return;
76     trigger = 1;
77
78     sigfillset(&all_masked);
79     sigdelset(&all_masked, SIGILL);
80     sigdelset(&all_masked, SIGTRAP);
81 #ifdef SIGEMT
82     sigdelset(&all_masked, SIGEMT);
83 #endif
84     sigdelset(&all_masked, SIGFPE);
85     sigdelset(&all_masked, SIGBUS);
86     sigdelset(&all_masked, SIGSEGV);
87
88     if ((e = getenv("OPENSSL_ppccap"))) {
89         OPENSSL_ppccap_P = strtoul(e, NULL, 0);
90         return;
91     }
92
93     OPENSSL_ppccap_P = 0;
94
95 #if defined(_AIX)
96     if (sizeof(size_t) == 4
97 # if defined(_SC_AIX_KERNEL_BITMODE)
98         && sysconf(_SC_AIX_KERNEL_BITMODE) != 64
99 # endif
100         )
101         return;
102 #endif
103
104     memset(&ill_act, 0, sizeof(ill_act));
105     ill_act.sa_handler = ill_handler;
106     ill_act.sa_mask = all_masked;
107
108     sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset);
109     sigaction(SIGILL, &ill_act, &ill_oact);
110
111     if (sizeof(size_t) == 4) {
112         if (sigsetjmp(ill_jmp, 1) == 0) {
113             OPENSSL_ppc64_probe();
114             OPENSSL_ppccap_P |= PPC_FPU64;
115         }
116     } else {
117         /*
118          * Wanted code detecting POWER6 CPU and setting PPC_FPU64
119          */
120     }
121
122     if (sigsetjmp(ill_jmp, 1) == 0) {
123         OPENSSL_altivec_probe();
124         OPENSSL_ppccap_P |= PPC_ALTIVEC;
125     }
126
127     sigaction(SIGILL, &ill_oact, NULL);
128     sigprocmask(SIG_SETMASK, &oset, NULL);
129 }