cpuid.c 5.7 KB

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