1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2011-2022 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <stdio.h> 11e1051a39Sopenharmony_ci#include <stdlib.h> 12e1051a39Sopenharmony_ci#include <string.h> 13e1051a39Sopenharmony_ci#include <setjmp.h> 14e1051a39Sopenharmony_ci#include <signal.h> 15e1051a39Sopenharmony_ci#include <openssl/crypto.h> 16e1051a39Sopenharmony_ci#ifdef __APPLE__ 17e1051a39Sopenharmony_ci#include <sys/sysctl.h> 18e1051a39Sopenharmony_ci#endif 19e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 20e1051a39Sopenharmony_ci 21e1051a39Sopenharmony_ci#include "arm_arch.h" 22e1051a39Sopenharmony_ci 23e1051a39Sopenharmony_ciunsigned int OPENSSL_armcap_P = 0; 24e1051a39Sopenharmony_ciunsigned int OPENSSL_arm_midr = 0; 25e1051a39Sopenharmony_ciunsigned int OPENSSL_armv8_rsa_neonized = 0; 26e1051a39Sopenharmony_ci 27e1051a39Sopenharmony_ci#if __ARM_MAX_ARCH__<7 28e1051a39Sopenharmony_civoid OPENSSL_cpuid_setup(void) 29e1051a39Sopenharmony_ci{ 30e1051a39Sopenharmony_ci} 31e1051a39Sopenharmony_ci 32e1051a39Sopenharmony_ciuint32_t OPENSSL_rdtsc(void) 33e1051a39Sopenharmony_ci{ 34e1051a39Sopenharmony_ci return 0; 35e1051a39Sopenharmony_ci} 36e1051a39Sopenharmony_ci#else 37e1051a39Sopenharmony_cistatic sigset_t all_masked; 38e1051a39Sopenharmony_ci 39e1051a39Sopenharmony_cistatic sigjmp_buf ill_jmp; 40e1051a39Sopenharmony_cistatic void ill_handler(int sig) 41e1051a39Sopenharmony_ci{ 42e1051a39Sopenharmony_ci siglongjmp(ill_jmp, sig); 43e1051a39Sopenharmony_ci} 44e1051a39Sopenharmony_ci 45e1051a39Sopenharmony_ci/* 46e1051a39Sopenharmony_ci * Following subroutines could have been inlined, but it's not all 47e1051a39Sopenharmony_ci * ARM compilers support inline assembler... 48e1051a39Sopenharmony_ci */ 49e1051a39Sopenharmony_civoid _armv7_neon_probe(void); 50e1051a39Sopenharmony_civoid _armv8_aes_probe(void); 51e1051a39Sopenharmony_civoid _armv8_sha1_probe(void); 52e1051a39Sopenharmony_civoid _armv8_sha256_probe(void); 53e1051a39Sopenharmony_civoid _armv8_pmull_probe(void); 54e1051a39Sopenharmony_ci# ifdef __aarch64__ 55e1051a39Sopenharmony_civoid _armv8_sha512_probe(void); 56e1051a39Sopenharmony_ciunsigned int _armv8_cpuid_probe(void); 57e1051a39Sopenharmony_ci# endif 58e1051a39Sopenharmony_ciuint32_t _armv7_tick(void); 59e1051a39Sopenharmony_ci 60e1051a39Sopenharmony_ciuint32_t OPENSSL_rdtsc(void) 61e1051a39Sopenharmony_ci{ 62e1051a39Sopenharmony_ci if (OPENSSL_armcap_P & ARMV7_TICK) 63e1051a39Sopenharmony_ci return _armv7_tick(); 64e1051a39Sopenharmony_ci else 65e1051a39Sopenharmony_ci return 0; 66e1051a39Sopenharmony_ci} 67e1051a39Sopenharmony_ci 68e1051a39Sopenharmony_ci# if defined(__GNUC__) && __GNUC__>=2 69e1051a39Sopenharmony_civoid OPENSSL_cpuid_setup(void) __attribute__ ((constructor)); 70e1051a39Sopenharmony_ci# endif 71e1051a39Sopenharmony_ci 72e1051a39Sopenharmony_ci# if defined(__GLIBC__) && defined(__GLIBC_PREREQ) 73e1051a39Sopenharmony_ci# if __GLIBC_PREREQ(2, 16) 74e1051a39Sopenharmony_ci# include <sys/auxv.h> 75e1051a39Sopenharmony_ci# define OSSL_IMPLEMENT_GETAUXVAL 76e1051a39Sopenharmony_ci# endif 77e1051a39Sopenharmony_ci# elif defined(__ANDROID_API__) 78e1051a39Sopenharmony_ci/* see https://developer.android.google.cn/ndk/guides/cpu-features */ 79e1051a39Sopenharmony_ci# if __ANDROID_API__ >= 18 80e1051a39Sopenharmony_ci# include <sys/auxv.h> 81e1051a39Sopenharmony_ci# define OSSL_IMPLEMENT_GETAUXVAL 82e1051a39Sopenharmony_ci# endif 83e1051a39Sopenharmony_ci# endif 84e1051a39Sopenharmony_ci# if defined(__FreeBSD__) 85e1051a39Sopenharmony_ci# include <sys/param.h> 86e1051a39Sopenharmony_ci# if __FreeBSD_version >= 1200000 87e1051a39Sopenharmony_ci# include <sys/auxv.h> 88e1051a39Sopenharmony_ci# define OSSL_IMPLEMENT_GETAUXVAL 89e1051a39Sopenharmony_ci 90e1051a39Sopenharmony_cistatic unsigned long getauxval(unsigned long key) 91e1051a39Sopenharmony_ci{ 92e1051a39Sopenharmony_ci unsigned long val = 0ul; 93e1051a39Sopenharmony_ci 94e1051a39Sopenharmony_ci if (elf_aux_info((int)key, &val, sizeof(val)) != 0) 95e1051a39Sopenharmony_ci return 0ul; 96e1051a39Sopenharmony_ci 97e1051a39Sopenharmony_ci return val; 98e1051a39Sopenharmony_ci} 99e1051a39Sopenharmony_ci# endif 100e1051a39Sopenharmony_ci# endif 101e1051a39Sopenharmony_ci 102e1051a39Sopenharmony_ci/* 103e1051a39Sopenharmony_ci * Android: according to https://developer.android.com/ndk/guides/cpu-features, 104e1051a39Sopenharmony_ci * getauxval is supported starting with API level 18 105e1051a39Sopenharmony_ci */ 106e1051a39Sopenharmony_ci# if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 18 107e1051a39Sopenharmony_ci# include <sys/auxv.h> 108e1051a39Sopenharmony_ci# define OSSL_IMPLEMENT_GETAUXVAL 109e1051a39Sopenharmony_ci# endif 110e1051a39Sopenharmony_ci 111e1051a39Sopenharmony_ci/* 112e1051a39Sopenharmony_ci * ARM puts the feature bits for Crypto Extensions in AT_HWCAP2, whereas 113e1051a39Sopenharmony_ci * AArch64 used AT_HWCAP. 114e1051a39Sopenharmony_ci */ 115e1051a39Sopenharmony_ci# ifndef AT_HWCAP 116e1051a39Sopenharmony_ci# define AT_HWCAP 16 117e1051a39Sopenharmony_ci# endif 118e1051a39Sopenharmony_ci# ifndef AT_HWCAP2 119e1051a39Sopenharmony_ci# define AT_HWCAP2 26 120e1051a39Sopenharmony_ci# endif 121e1051a39Sopenharmony_ci# if defined(__arm__) || defined (__arm) 122e1051a39Sopenharmony_ci# define HWCAP AT_HWCAP 123e1051a39Sopenharmony_ci# define HWCAP_NEON (1 << 12) 124e1051a39Sopenharmony_ci 125e1051a39Sopenharmony_ci# define HWCAP_CE AT_HWCAP2 126e1051a39Sopenharmony_ci# define HWCAP_CE_AES (1 << 0) 127e1051a39Sopenharmony_ci# define HWCAP_CE_PMULL (1 << 1) 128e1051a39Sopenharmony_ci# define HWCAP_CE_SHA1 (1 << 2) 129e1051a39Sopenharmony_ci# define HWCAP_CE_SHA256 (1 << 3) 130e1051a39Sopenharmony_ci# elif defined(__aarch64__) 131e1051a39Sopenharmony_ci# define HWCAP AT_HWCAP 132e1051a39Sopenharmony_ci# define HWCAP_NEON (1 << 1) 133e1051a39Sopenharmony_ci 134e1051a39Sopenharmony_ci# define HWCAP_CE HWCAP 135e1051a39Sopenharmony_ci# define HWCAP_CE_AES (1 << 3) 136e1051a39Sopenharmony_ci# define HWCAP_CE_PMULL (1 << 4) 137e1051a39Sopenharmony_ci# define HWCAP_CE_SHA1 (1 << 5) 138e1051a39Sopenharmony_ci# define HWCAP_CE_SHA256 (1 << 6) 139e1051a39Sopenharmony_ci# define HWCAP_CPUID (1 << 11) 140e1051a39Sopenharmony_ci# define HWCAP_CE_SHA512 (1 << 21) 141e1051a39Sopenharmony_ci# endif 142e1051a39Sopenharmony_ci 143e1051a39Sopenharmony_civoid OPENSSL_cpuid_setup(void) 144e1051a39Sopenharmony_ci{ 145e1051a39Sopenharmony_ci const char *e; 146e1051a39Sopenharmony_ci struct sigaction ill_oact, ill_act; 147e1051a39Sopenharmony_ci sigset_t oset; 148e1051a39Sopenharmony_ci static int trigger = 0; 149e1051a39Sopenharmony_ci 150e1051a39Sopenharmony_ci if (trigger) 151e1051a39Sopenharmony_ci return; 152e1051a39Sopenharmony_ci trigger = 1; 153e1051a39Sopenharmony_ci 154e1051a39Sopenharmony_ci OPENSSL_armcap_P = 0; 155e1051a39Sopenharmony_ci 156e1051a39Sopenharmony_ci if ((e = getenv("OPENSSL_armcap"))) { 157e1051a39Sopenharmony_ci OPENSSL_armcap_P = (unsigned int)strtoul(e, NULL, 0); 158e1051a39Sopenharmony_ci return; 159e1051a39Sopenharmony_ci } 160e1051a39Sopenharmony_ci 161e1051a39Sopenharmony_ci# if defined(__APPLE__) 162e1051a39Sopenharmony_ci# if !defined(__aarch64__) 163e1051a39Sopenharmony_ci /* 164e1051a39Sopenharmony_ci * Capability probing by catching SIGILL appears to be problematic 165e1051a39Sopenharmony_ci * on iOS. But since Apple universe is "monocultural", it's actually 166e1051a39Sopenharmony_ci * possible to simply set pre-defined processor capability mask. 167e1051a39Sopenharmony_ci */ 168e1051a39Sopenharmony_ci if (1) { 169e1051a39Sopenharmony_ci OPENSSL_armcap_P = ARMV7_NEON; 170e1051a39Sopenharmony_ci return; 171e1051a39Sopenharmony_ci } 172e1051a39Sopenharmony_ci /* 173e1051a39Sopenharmony_ci * One could do same even for __aarch64__ iOS builds. It's not done 174e1051a39Sopenharmony_ci * exclusively for reasons of keeping code unified across platforms. 175e1051a39Sopenharmony_ci * Unified code works because it never triggers SIGILL on Apple 176e1051a39Sopenharmony_ci * devices... 177e1051a39Sopenharmony_ci */ 178e1051a39Sopenharmony_ci# else 179e1051a39Sopenharmony_ci { 180e1051a39Sopenharmony_ci unsigned int sha512; 181e1051a39Sopenharmony_ci size_t len = sizeof(sha512); 182e1051a39Sopenharmony_ci 183e1051a39Sopenharmony_ci if (sysctlbyname("hw.optional.armv8_2_sha512", &sha512, &len, NULL, 0) == 0 && sha512 == 1) 184e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV8_SHA512; 185e1051a39Sopenharmony_ci } 186e1051a39Sopenharmony_ci# endif 187e1051a39Sopenharmony_ci# endif 188e1051a39Sopenharmony_ci 189e1051a39Sopenharmony_ci# ifdef OSSL_IMPLEMENT_GETAUXVAL 190e1051a39Sopenharmony_ci if (getauxval(HWCAP) & HWCAP_NEON) { 191e1051a39Sopenharmony_ci unsigned long hwcap = getauxval(HWCAP_CE); 192e1051a39Sopenharmony_ci 193e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV7_NEON; 194e1051a39Sopenharmony_ci 195e1051a39Sopenharmony_ci if (hwcap & HWCAP_CE_AES) 196e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV8_AES; 197e1051a39Sopenharmony_ci 198e1051a39Sopenharmony_ci if (hwcap & HWCAP_CE_PMULL) 199e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV8_PMULL; 200e1051a39Sopenharmony_ci 201e1051a39Sopenharmony_ci if (hwcap & HWCAP_CE_SHA1) 202e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV8_SHA1; 203e1051a39Sopenharmony_ci 204e1051a39Sopenharmony_ci if (hwcap & HWCAP_CE_SHA256) 205e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV8_SHA256; 206e1051a39Sopenharmony_ci 207e1051a39Sopenharmony_ci# ifdef __aarch64__ 208e1051a39Sopenharmony_ci if (hwcap & HWCAP_CE_SHA512) 209e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV8_SHA512; 210e1051a39Sopenharmony_ci 211e1051a39Sopenharmony_ci if (hwcap & HWCAP_CPUID) 212e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV8_CPUID; 213e1051a39Sopenharmony_ci# endif 214e1051a39Sopenharmony_ci } 215e1051a39Sopenharmony_ci# endif 216e1051a39Sopenharmony_ci 217e1051a39Sopenharmony_ci sigfillset(&all_masked); 218e1051a39Sopenharmony_ci sigdelset(&all_masked, SIGILL); 219e1051a39Sopenharmony_ci sigdelset(&all_masked, SIGTRAP); 220e1051a39Sopenharmony_ci sigdelset(&all_masked, SIGFPE); 221e1051a39Sopenharmony_ci sigdelset(&all_masked, SIGBUS); 222e1051a39Sopenharmony_ci sigdelset(&all_masked, SIGSEGV); 223e1051a39Sopenharmony_ci 224e1051a39Sopenharmony_ci memset(&ill_act, 0, sizeof(ill_act)); 225e1051a39Sopenharmony_ci ill_act.sa_handler = ill_handler; 226e1051a39Sopenharmony_ci ill_act.sa_mask = all_masked; 227e1051a39Sopenharmony_ci 228e1051a39Sopenharmony_ci sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset); 229e1051a39Sopenharmony_ci sigaction(SIGILL, &ill_act, &ill_oact); 230e1051a39Sopenharmony_ci 231e1051a39Sopenharmony_ci /* If we used getauxval, we already have all the values */ 232e1051a39Sopenharmony_ci# ifndef OSSL_IMPLEMENT_GETAUXVAL 233e1051a39Sopenharmony_ci if (sigsetjmp(ill_jmp, 1) == 0) { 234e1051a39Sopenharmony_ci _armv7_neon_probe(); 235e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV7_NEON; 236e1051a39Sopenharmony_ci if (sigsetjmp(ill_jmp, 1) == 0) { 237e1051a39Sopenharmony_ci _armv8_pmull_probe(); 238e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV8_PMULL | ARMV8_AES; 239e1051a39Sopenharmony_ci } else if (sigsetjmp(ill_jmp, 1) == 0) { 240e1051a39Sopenharmony_ci _armv8_aes_probe(); 241e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV8_AES; 242e1051a39Sopenharmony_ci } 243e1051a39Sopenharmony_ci if (sigsetjmp(ill_jmp, 1) == 0) { 244e1051a39Sopenharmony_ci _armv8_sha1_probe(); 245e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV8_SHA1; 246e1051a39Sopenharmony_ci } 247e1051a39Sopenharmony_ci if (sigsetjmp(ill_jmp, 1) == 0) { 248e1051a39Sopenharmony_ci _armv8_sha256_probe(); 249e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV8_SHA256; 250e1051a39Sopenharmony_ci } 251e1051a39Sopenharmony_ci# if defined(__aarch64__) && !defined(__APPLE__) 252e1051a39Sopenharmony_ci if (sigsetjmp(ill_jmp, 1) == 0) { 253e1051a39Sopenharmony_ci _armv8_sha512_probe(); 254e1051a39Sopenharmony_ci OPENSSL_armcap_P |= ARMV8_SHA512; 255e1051a39Sopenharmony_ci } 256e1051a39Sopenharmony_ci# endif 257e1051a39Sopenharmony_ci } 258e1051a39Sopenharmony_ci# endif 259e1051a39Sopenharmony_ci 260e1051a39Sopenharmony_ci /* 261e1051a39Sopenharmony_ci * Probing for ARMV7_TICK is known to produce unreliable results, 262e1051a39Sopenharmony_ci * so we will only use the feature when the user explicitly enables 263e1051a39Sopenharmony_ci * it with OPENSSL_armcap. 264e1051a39Sopenharmony_ci */ 265e1051a39Sopenharmony_ci 266e1051a39Sopenharmony_ci sigaction(SIGILL, &ill_oact, NULL); 267e1051a39Sopenharmony_ci sigprocmask(SIG_SETMASK, &oset, NULL); 268e1051a39Sopenharmony_ci 269e1051a39Sopenharmony_ci# ifdef __aarch64__ 270e1051a39Sopenharmony_ci if (OPENSSL_armcap_P & ARMV8_CPUID) 271e1051a39Sopenharmony_ci OPENSSL_arm_midr = _armv8_cpuid_probe(); 272e1051a39Sopenharmony_ci 273e1051a39Sopenharmony_ci if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) || 274e1051a39Sopenharmony_ci MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N1)) && 275e1051a39Sopenharmony_ci (OPENSSL_armcap_P & ARMV7_NEON)) { 276e1051a39Sopenharmony_ci OPENSSL_armv8_rsa_neonized = 1; 277e1051a39Sopenharmony_ci } 278e1051a39Sopenharmony_ci# endif 279e1051a39Sopenharmony_ci} 280e1051a39Sopenharmony_ci#endif 281