1/* 2 * Copyright 2009-2021 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <setjmp.h> 14#include <signal.h> 15#include <unistd.h> 16#if defined(__linux) || defined(_AIX) 17# include <sys/utsname.h> 18#endif 19#if defined(_AIX53) /* defined even on post-5.3 */ 20# include <sys/systemcfg.h> 21# if !defined(__power_set) 22# define __power_set(a) (_system_configuration.implementation & (a)) 23# endif 24#endif 25#if defined(__APPLE__) && defined(__MACH__) 26# include <sys/types.h> 27# include <sys/sysctl.h> 28#endif 29#if defined(__NetBSD__) 30# include <sys/param.h> 31# include <sys/sysctl.h> 32#endif 33#include <openssl/crypto.h> 34#include "internal/cryptlib.h" 35#include "crypto/ppc_arch.h" 36 37unsigned int OPENSSL_ppccap_P = 0; 38 39static sigset_t all_masked; 40 41static sigjmp_buf ill_jmp; 42static void ill_handler(int sig) 43{ 44 siglongjmp(ill_jmp, sig); 45} 46 47void OPENSSL_fpu_probe(void); 48void OPENSSL_ppc64_probe(void); 49void OPENSSL_altivec_probe(void); 50void OPENSSL_crypto207_probe(void); 51void OPENSSL_madd300_probe(void); 52 53long OPENSSL_rdtsc_mftb(void); 54long OPENSSL_rdtsc_mfspr268(void); 55 56uint32_t OPENSSL_rdtsc(void) 57{ 58 if (OPENSSL_ppccap_P & PPC_MFTB) 59 return OPENSSL_rdtsc_mftb(); 60 else if (OPENSSL_ppccap_P & PPC_MFSPR268) 61 return OPENSSL_rdtsc_mfspr268(); 62 else 63 return 0; 64} 65 66size_t OPENSSL_instrument_bus_mftb(unsigned int *, size_t); 67size_t OPENSSL_instrument_bus_mfspr268(unsigned int *, size_t); 68 69size_t OPENSSL_instrument_bus(unsigned int *out, size_t cnt) 70{ 71 if (OPENSSL_ppccap_P & PPC_MFTB) 72 return OPENSSL_instrument_bus_mftb(out, cnt); 73 else if (OPENSSL_ppccap_P & PPC_MFSPR268) 74 return OPENSSL_instrument_bus_mfspr268(out, cnt); 75 else 76 return 0; 77} 78 79size_t OPENSSL_instrument_bus2_mftb(unsigned int *, size_t, size_t); 80size_t OPENSSL_instrument_bus2_mfspr268(unsigned int *, size_t, size_t); 81 82size_t OPENSSL_instrument_bus2(unsigned int *out, size_t cnt, size_t max) 83{ 84 if (OPENSSL_ppccap_P & PPC_MFTB) 85 return OPENSSL_instrument_bus2_mftb(out, cnt, max); 86 else if (OPENSSL_ppccap_P & PPC_MFSPR268) 87 return OPENSSL_instrument_bus2_mfspr268(out, cnt, max); 88 else 89 return 0; 90} 91 92#if defined(__GLIBC__) && defined(__GLIBC_PREREQ) 93# if __GLIBC_PREREQ(2, 16) 94# include <sys/auxv.h> 95# define OSSL_IMPLEMENT_GETAUXVAL 96# elif defined(__ANDROID_API__) 97/* see https://developer.android.google.cn/ndk/guides/cpu-features */ 98# if __ANDROID_API__ >= 18 99# include <sys/auxv.h> 100# define OSSL_IMPLEMENT_GETAUXVAL 101# endif 102# endif 103#endif 104 105#if defined(__FreeBSD__) 106# include <sys/param.h> 107# if __FreeBSD_version >= 1200000 108# include <sys/auxv.h> 109# define OSSL_IMPLEMENT_GETAUXVAL 110 111static unsigned long getauxval(unsigned long key) 112{ 113 unsigned long val = 0ul; 114 115 if (elf_aux_info((int)key, &val, sizeof(val)) != 0) 116 return 0ul; 117 118 return val; 119} 120# endif 121#endif 122 123/* I wish <sys/auxv.h> was universally available */ 124#define HWCAP 16 /* AT_HWCAP */ 125#define HWCAP_PPC64 (1U << 30) 126#define HWCAP_ALTIVEC (1U << 28) 127#define HWCAP_FPU (1U << 27) 128#define HWCAP_POWER6_EXT (1U << 9) 129#define HWCAP_VSX (1U << 7) 130 131#define HWCAP2 26 /* AT_HWCAP2 */ 132#define HWCAP_VEC_CRYPTO (1U << 25) 133#define HWCAP_ARCH_3_00 (1U << 23) 134 135# if defined(__GNUC__) && __GNUC__>=2 136__attribute__ ((constructor)) 137# endif 138void OPENSSL_cpuid_setup(void) 139{ 140 char *e; 141 struct sigaction ill_oact, ill_act; 142 sigset_t oset; 143 static int trigger = 0; 144 145 if (trigger) 146 return; 147 trigger = 1; 148 149 if ((e = getenv("OPENSSL_ppccap"))) { 150 OPENSSL_ppccap_P = strtoul(e, NULL, 0); 151 return; 152 } 153 154 OPENSSL_ppccap_P = 0; 155 156#if defined(_AIX) 157 OPENSSL_ppccap_P |= PPC_FPU; 158 159 if (sizeof(size_t) == 4) { 160 struct utsname uts; 161# if defined(_SC_AIX_KERNEL_BITMODE) 162 if (sysconf(_SC_AIX_KERNEL_BITMODE) != 64) 163 return; 164# endif 165 if (uname(&uts) != 0 || atoi(uts.version) < 6) 166 return; 167 } 168 169# if defined(__power_set) 170 /* 171 * Value used in __power_set is a single-bit 1<<n one denoting 172 * specific processor class. Incidentally 0xffffffff<<n can be 173 * used to denote specific processor and its successors. 174 */ 175 if (sizeof(size_t) == 4) { 176 /* In 32-bit case PPC_FPU64 is always fastest [if option] */ 177 if (__power_set(0xffffffffU<<13)) /* POWER5 and later */ 178 OPENSSL_ppccap_P |= PPC_FPU64; 179 } else { 180 /* In 64-bit case PPC_FPU64 is fastest only on POWER6 */ 181 if (__power_set(0x1U<<14)) /* POWER6 */ 182 OPENSSL_ppccap_P |= PPC_FPU64; 183 } 184 185 if (__power_set(0xffffffffU<<14)) /* POWER6 and later */ 186 OPENSSL_ppccap_P |= PPC_ALTIVEC; 187 188 if (__power_set(0xffffffffU<<16)) /* POWER8 and later */ 189 OPENSSL_ppccap_P |= PPC_CRYPTO207; 190 191 if (__power_set(0xffffffffU<<17)) /* POWER9 and later */ 192 OPENSSL_ppccap_P |= PPC_MADD300; 193 194 return; 195# endif 196#endif 197 198#if defined(__APPLE__) && defined(__MACH__) 199 OPENSSL_ppccap_P |= PPC_FPU; 200 201 { 202 int val; 203 size_t len = sizeof(val); 204 205 if (sysctlbyname("hw.optional.64bitops", &val, &len, NULL, 0) == 0) { 206 if (val) 207 OPENSSL_ppccap_P |= PPC_FPU64; 208 } 209 210 len = sizeof(val); 211 if (sysctlbyname("hw.optional.altivec", &val, &len, NULL, 0) == 0) { 212 if (val) 213 OPENSSL_ppccap_P |= PPC_ALTIVEC; 214 } 215 216 return; 217 } 218#endif 219 220#ifdef OSSL_IMPLEMENT_GETAUXVAL 221 { 222 unsigned long hwcap = getauxval(HWCAP); 223 unsigned long hwcap2 = getauxval(HWCAP2); 224 225 if (hwcap & HWCAP_FPU) { 226 OPENSSL_ppccap_P |= PPC_FPU; 227 228 if (sizeof(size_t) == 4) { 229 /* In 32-bit case PPC_FPU64 is always fastest [if option] */ 230 if (hwcap & HWCAP_PPC64) 231 OPENSSL_ppccap_P |= PPC_FPU64; 232 } else { 233 /* In 64-bit case PPC_FPU64 is fastest only on POWER6 */ 234 if (hwcap & HWCAP_POWER6_EXT) 235 OPENSSL_ppccap_P |= PPC_FPU64; 236 } 237 } 238 239 if (hwcap & HWCAP_ALTIVEC) { 240 OPENSSL_ppccap_P |= PPC_ALTIVEC; 241 242 if ((hwcap & HWCAP_VSX) && (hwcap2 & HWCAP_VEC_CRYPTO)) 243 OPENSSL_ppccap_P |= PPC_CRYPTO207; 244 } 245 246 if (hwcap2 & HWCAP_ARCH_3_00) { 247 OPENSSL_ppccap_P |= PPC_MADD300; 248 } 249 } 250#endif 251 252 sigfillset(&all_masked); 253 sigdelset(&all_masked, SIGILL); 254 sigdelset(&all_masked, SIGTRAP); 255#ifdef SIGEMT 256 sigdelset(&all_masked, SIGEMT); 257#endif 258 sigdelset(&all_masked, SIGFPE); 259 sigdelset(&all_masked, SIGBUS); 260 sigdelset(&all_masked, SIGSEGV); 261 262 memset(&ill_act, 0, sizeof(ill_act)); 263 ill_act.sa_handler = ill_handler; 264 ill_act.sa_mask = all_masked; 265 266 sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset); 267 sigaction(SIGILL, &ill_act, &ill_oact); 268 269#ifndef OSSL_IMPLEMENT_GETAUXVAL 270# ifdef __NetBSD__ 271 int error, val; 272 size_t len = sizeof(val); 273 274 /* 275 * If machdep.fpu_present == 0, FPU is absent and emulated by 276 * software. In that case, using FPU instructions hurts rather 277 * than helps performance, and the software is unlikely to run in 278 * constant time so it would expose us to timing side channel 279 * attacks. So don't do it! 280 */ 281 error = sysctlbyname("machdep.fpu_present", &val, &len, NULL, 0); 282 if (error != 0 || (error == 0 && val != 0)) 283# endif 284 if (sigsetjmp(ill_jmp,1) == 0) { 285 OPENSSL_fpu_probe(); 286 OPENSSL_ppccap_P |= PPC_FPU; 287 288 if (sizeof(size_t) == 4) { 289# ifdef __linux 290 struct utsname uts; 291 if (uname(&uts) == 0 && strcmp(uts.machine, "ppc64") == 0) 292# endif 293 if (sigsetjmp(ill_jmp, 1) == 0) { 294 OPENSSL_ppc64_probe(); 295 OPENSSL_ppccap_P |= PPC_FPU64; 296 } 297 } else { 298 /* 299 * Wanted code detecting POWER6 CPU and setting PPC_FPU64 300 */ 301 } 302 } 303 304 if (sigsetjmp(ill_jmp, 1) == 0) { 305 OPENSSL_altivec_probe(); 306 OPENSSL_ppccap_P |= PPC_ALTIVEC; 307 if (sigsetjmp(ill_jmp, 1) == 0) { 308 OPENSSL_crypto207_probe(); 309 OPENSSL_ppccap_P |= PPC_CRYPTO207; 310 } 311 } 312 313 if (sigsetjmp(ill_jmp, 1) == 0) { 314 OPENSSL_madd300_probe(); 315 OPENSSL_ppccap_P |= PPC_MADD300; 316 } 317#endif 318 319 if (sigsetjmp(ill_jmp, 1) == 0) { 320 OPENSSL_rdtsc_mftb(); 321 OPENSSL_ppccap_P |= PPC_MFTB; 322 } else if (sigsetjmp(ill_jmp, 1) == 0) { 323 OPENSSL_rdtsc_mfspr268(); 324 OPENSSL_ppccap_P |= PPC_MFSPR268; 325 } 326 327 sigaction(SIGILL, &ill_oact, NULL); 328 sigprocmask(SIG_SETMASK, &oset, NULL); 329} 330