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