1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 1998-2021 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 "e_os.h" 11e1051a39Sopenharmony_ci#include "crypto/cryptlib.h" 12e1051a39Sopenharmony_ci 13e1051a39Sopenharmony_ci#if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ 14e1051a39Sopenharmony_ci defined(__x86_64) || defined(__x86_64__) || \ 15e1051a39Sopenharmony_ci defined(_M_AMD64) || defined(_M_X64) 16e1051a39Sopenharmony_ci 17e1051a39Sopenharmony_ciextern unsigned int OPENSSL_ia32cap_P[4]; 18e1051a39Sopenharmony_ci 19e1051a39Sopenharmony_ci# if defined(OPENSSL_CPUID_OBJ) 20e1051a39Sopenharmony_ci 21e1051a39Sopenharmony_ci/* 22e1051a39Sopenharmony_ci * Purpose of these minimalistic and character-type-agnostic subroutines 23e1051a39Sopenharmony_ci * is to break dependency on MSVCRT (on Windows) and locale. This makes 24e1051a39Sopenharmony_ci * OPENSSL_cpuid_setup safe to use as "constructor". "Character-type- 25e1051a39Sopenharmony_ci * agnostic" means that they work with either wide or 8-bit characters, 26e1051a39Sopenharmony_ci * exploiting the fact that first 127 characters can be simply casted 27e1051a39Sopenharmony_ci * between the sets, while the rest would be simply rejected by ossl_is* 28e1051a39Sopenharmony_ci * subroutines. 29e1051a39Sopenharmony_ci */ 30e1051a39Sopenharmony_ci# ifdef _WIN32 31e1051a39Sopenharmony_citypedef WCHAR variant_char; 32e1051a39Sopenharmony_ci 33e1051a39Sopenharmony_cistatic variant_char *ossl_getenv(const char *name) 34e1051a39Sopenharmony_ci{ 35e1051a39Sopenharmony_ci /* 36e1051a39Sopenharmony_ci * Since we pull only one environment variable, it's simpler to 37e1051a39Sopenharmony_ci * to just ignore |name| and use equivalent wide-char L-literal. 38e1051a39Sopenharmony_ci * As well as to ignore excessively long values... 39e1051a39Sopenharmony_ci */ 40e1051a39Sopenharmony_ci static WCHAR value[48]; 41e1051a39Sopenharmony_ci DWORD len = GetEnvironmentVariableW(L"OPENSSL_ia32cap", value, 48); 42e1051a39Sopenharmony_ci 43e1051a39Sopenharmony_ci return (len > 0 && len < 48) ? value : NULL; 44e1051a39Sopenharmony_ci} 45e1051a39Sopenharmony_ci# else 46e1051a39Sopenharmony_citypedef char variant_char; 47e1051a39Sopenharmony_ci# define ossl_getenv getenv 48e1051a39Sopenharmony_ci# endif 49e1051a39Sopenharmony_ci 50e1051a39Sopenharmony_ci# include "crypto/ctype.h" 51e1051a39Sopenharmony_ci 52e1051a39Sopenharmony_cistatic int todigit(variant_char c) 53e1051a39Sopenharmony_ci{ 54e1051a39Sopenharmony_ci if (ossl_isdigit(c)) 55e1051a39Sopenharmony_ci return c - '0'; 56e1051a39Sopenharmony_ci else if (ossl_isxdigit(c)) 57e1051a39Sopenharmony_ci return ossl_tolower(c) - 'a' + 10; 58e1051a39Sopenharmony_ci 59e1051a39Sopenharmony_ci /* return largest base value to make caller terminate the loop */ 60e1051a39Sopenharmony_ci return 16; 61e1051a39Sopenharmony_ci} 62e1051a39Sopenharmony_ci 63e1051a39Sopenharmony_cistatic uint64_t ossl_strtouint64(const variant_char *str) 64e1051a39Sopenharmony_ci{ 65e1051a39Sopenharmony_ci uint64_t ret = 0; 66e1051a39Sopenharmony_ci unsigned int digit, base = 10; 67e1051a39Sopenharmony_ci 68e1051a39Sopenharmony_ci if (*str == '0') { 69e1051a39Sopenharmony_ci base = 8, str++; 70e1051a39Sopenharmony_ci if (ossl_tolower(*str) == 'x') 71e1051a39Sopenharmony_ci base = 16, str++; 72e1051a39Sopenharmony_ci } 73e1051a39Sopenharmony_ci 74e1051a39Sopenharmony_ci while((digit = todigit(*str++)) < base) 75e1051a39Sopenharmony_ci ret = ret * base + digit; 76e1051a39Sopenharmony_ci 77e1051a39Sopenharmony_ci return ret; 78e1051a39Sopenharmony_ci} 79e1051a39Sopenharmony_ci 80e1051a39Sopenharmony_cistatic variant_char *ossl_strchr(const variant_char *str, char srch) 81e1051a39Sopenharmony_ci{ variant_char c; 82e1051a39Sopenharmony_ci 83e1051a39Sopenharmony_ci while((c = *str)) { 84e1051a39Sopenharmony_ci if (c == srch) 85e1051a39Sopenharmony_ci return (variant_char *)str; 86e1051a39Sopenharmony_ci str++; 87e1051a39Sopenharmony_ci } 88e1051a39Sopenharmony_ci 89e1051a39Sopenharmony_ci return NULL; 90e1051a39Sopenharmony_ci} 91e1051a39Sopenharmony_ci 92e1051a39Sopenharmony_ci# define OPENSSL_CPUID_SETUP 93e1051a39Sopenharmony_citypedef uint64_t IA32CAP; 94e1051a39Sopenharmony_ci 95e1051a39Sopenharmony_civoid OPENSSL_cpuid_setup(void) 96e1051a39Sopenharmony_ci{ 97e1051a39Sopenharmony_ci static int trigger = 0; 98e1051a39Sopenharmony_ci IA32CAP OPENSSL_ia32_cpuid(unsigned int *); 99e1051a39Sopenharmony_ci IA32CAP vec; 100e1051a39Sopenharmony_ci const variant_char *env; 101e1051a39Sopenharmony_ci 102e1051a39Sopenharmony_ci if (trigger) 103e1051a39Sopenharmony_ci return; 104e1051a39Sopenharmony_ci 105e1051a39Sopenharmony_ci trigger = 1; 106e1051a39Sopenharmony_ci if ((env = ossl_getenv("OPENSSL_ia32cap")) != NULL) { 107e1051a39Sopenharmony_ci int off = (env[0] == '~') ? 1 : 0; 108e1051a39Sopenharmony_ci 109e1051a39Sopenharmony_ci vec = ossl_strtouint64(env + off); 110e1051a39Sopenharmony_ci 111e1051a39Sopenharmony_ci if (off) { 112e1051a39Sopenharmony_ci IA32CAP mask = vec; 113e1051a39Sopenharmony_ci vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P) & ~mask; 114e1051a39Sopenharmony_ci if (mask & (1<<24)) { 115e1051a39Sopenharmony_ci /* 116e1051a39Sopenharmony_ci * User disables FXSR bit, mask even other capabilities 117e1051a39Sopenharmony_ci * that operate exclusively on XMM, so we don't have to 118e1051a39Sopenharmony_ci * double-check all the time. We mask PCLMULQDQ, AMD XOP, 119e1051a39Sopenharmony_ci * AES-NI and AVX. Formally speaking we don't have to 120e1051a39Sopenharmony_ci * do it in x86_64 case, but we can safely assume that 121e1051a39Sopenharmony_ci * x86_64 users won't actually flip this flag. 122e1051a39Sopenharmony_ci */ 123e1051a39Sopenharmony_ci vec &= ~((IA32CAP)(1<<1|1<<11|1<<25|1<<28) << 32); 124e1051a39Sopenharmony_ci } 125e1051a39Sopenharmony_ci } else if (env[0] == ':') { 126e1051a39Sopenharmony_ci vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P); 127e1051a39Sopenharmony_ci } 128e1051a39Sopenharmony_ci 129e1051a39Sopenharmony_ci if ((env = ossl_strchr(env, ':')) != NULL) { 130e1051a39Sopenharmony_ci IA32CAP vecx; 131e1051a39Sopenharmony_ci 132e1051a39Sopenharmony_ci env++; 133e1051a39Sopenharmony_ci off = (env[0] == '~') ? 1 : 0; 134e1051a39Sopenharmony_ci vecx = ossl_strtouint64(env + off); 135e1051a39Sopenharmony_ci if (off) { 136e1051a39Sopenharmony_ci OPENSSL_ia32cap_P[2] &= ~(unsigned int)vecx; 137e1051a39Sopenharmony_ci OPENSSL_ia32cap_P[3] &= ~(unsigned int)(vecx >> 32); 138e1051a39Sopenharmony_ci } else { 139e1051a39Sopenharmony_ci OPENSSL_ia32cap_P[2] = (unsigned int)vecx; 140e1051a39Sopenharmony_ci OPENSSL_ia32cap_P[3] = (unsigned int)(vecx >> 32); 141e1051a39Sopenharmony_ci } 142e1051a39Sopenharmony_ci } else { 143e1051a39Sopenharmony_ci OPENSSL_ia32cap_P[2] = 0; 144e1051a39Sopenharmony_ci OPENSSL_ia32cap_P[3] = 0; 145e1051a39Sopenharmony_ci } 146e1051a39Sopenharmony_ci } else { 147e1051a39Sopenharmony_ci vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P); 148e1051a39Sopenharmony_ci } 149e1051a39Sopenharmony_ci 150e1051a39Sopenharmony_ci /* 151e1051a39Sopenharmony_ci * |(1<<10) sets a reserved bit to signal that variable 152e1051a39Sopenharmony_ci * was initialized already... This is to avoid interference 153e1051a39Sopenharmony_ci * with cpuid snippets in ELF .init segment. 154e1051a39Sopenharmony_ci */ 155e1051a39Sopenharmony_ci OPENSSL_ia32cap_P[0] = (unsigned int)vec | (1 << 10); 156e1051a39Sopenharmony_ci OPENSSL_ia32cap_P[1] = (unsigned int)(vec >> 32); 157e1051a39Sopenharmony_ci} 158e1051a39Sopenharmony_ci# else 159e1051a39Sopenharmony_ciunsigned int OPENSSL_ia32cap_P[4]; 160e1051a39Sopenharmony_ci# endif 161e1051a39Sopenharmony_ci#endif 162e1051a39Sopenharmony_ci 163e1051a39Sopenharmony_ci#ifndef OPENSSL_CPUID_OBJ 164e1051a39Sopenharmony_ci# ifndef OPENSSL_CPUID_SETUP 165e1051a39Sopenharmony_civoid OPENSSL_cpuid_setup(void) 166e1051a39Sopenharmony_ci{ 167e1051a39Sopenharmony_ci} 168e1051a39Sopenharmony_ci# endif 169e1051a39Sopenharmony_ci 170e1051a39Sopenharmony_ci/* 171e1051a39Sopenharmony_ci * The rest are functions that are defined in the same assembler files as 172e1051a39Sopenharmony_ci * the CPUID functionality. 173e1051a39Sopenharmony_ci */ 174e1051a39Sopenharmony_ci 175e1051a39Sopenharmony_ci/* 176e1051a39Sopenharmony_ci * The volatile is used to to ensure that the compiler generates code that reads 177e1051a39Sopenharmony_ci * all values from the array and doesn't try to optimize this away. The standard 178e1051a39Sopenharmony_ci * doesn't actually require this behavior if the original data pointed to is 179e1051a39Sopenharmony_ci * not volatile, but compilers do this in practice anyway. 180e1051a39Sopenharmony_ci * 181e1051a39Sopenharmony_ci * There are also assembler versions of this function. 182e1051a39Sopenharmony_ci */ 183e1051a39Sopenharmony_ci# undef CRYPTO_memcmp 184e1051a39Sopenharmony_ciint CRYPTO_memcmp(const void * in_a, const void * in_b, size_t len) 185e1051a39Sopenharmony_ci{ 186e1051a39Sopenharmony_ci size_t i; 187e1051a39Sopenharmony_ci const volatile unsigned char *a = in_a; 188e1051a39Sopenharmony_ci const volatile unsigned char *b = in_b; 189e1051a39Sopenharmony_ci unsigned char x = 0; 190e1051a39Sopenharmony_ci 191e1051a39Sopenharmony_ci for (i = 0; i < len; i++) 192e1051a39Sopenharmony_ci x |= a[i] ^ b[i]; 193e1051a39Sopenharmony_ci 194e1051a39Sopenharmony_ci return x; 195e1051a39Sopenharmony_ci} 196e1051a39Sopenharmony_ci 197e1051a39Sopenharmony_ci/* 198e1051a39Sopenharmony_ci * For systems that don't provide an instruction counter register or equivalent. 199e1051a39Sopenharmony_ci */ 200e1051a39Sopenharmony_ciuint32_t OPENSSL_rdtsc(void) 201e1051a39Sopenharmony_ci{ 202e1051a39Sopenharmony_ci return 0; 203e1051a39Sopenharmony_ci} 204e1051a39Sopenharmony_ci 205e1051a39Sopenharmony_cisize_t OPENSSL_instrument_bus(unsigned int *out, size_t cnt) 206e1051a39Sopenharmony_ci{ 207e1051a39Sopenharmony_ci return 0; 208e1051a39Sopenharmony_ci} 209e1051a39Sopenharmony_ci 210e1051a39Sopenharmony_cisize_t OPENSSL_instrument_bus2(unsigned int *out, size_t cnt, size_t max) 211e1051a39Sopenharmony_ci{ 212e1051a39Sopenharmony_ci return 0; 213e1051a39Sopenharmony_ci} 214e1051a39Sopenharmony_ci#endif 215