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