cpu-arm-linux.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /* Copyright (c) 2018, Google Inc.
  2. *
  3. * Permission to use, copy, modify, and/or distribute this software for any
  4. * purpose with or without fee is hereby granted, provided that the above
  5. * copyright notice and this permission notice appear in all copies.
  6. *
  7. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
  14. #ifndef OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H
  15. #define OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H
  16. #include <openssl/base.h>
  17. #include <string.h>
  18. #include "internal.h"
  19. #if defined(__cplusplus)
  20. extern "C" {
  21. #endif
  22. // The cpuinfo parser lives in a header file so it may be accessible from
  23. // cross-platform fuzzers without adding code to those platforms normally.
  24. #define HWCAP_NEON (1 << 12)
  25. // See /usr/include/asm/hwcap.h on an ARM installation for the source of
  26. // these values.
  27. #define HWCAP2_AES (1 << 0)
  28. #define HWCAP2_PMULL (1 << 1)
  29. #define HWCAP2_SHA1 (1 << 2)
  30. #define HWCAP2_SHA2 (1 << 3)
  31. typedef struct {
  32. const char *data;
  33. size_t len;
  34. } STRING_PIECE;
  35. static int STRING_PIECE_equals(const STRING_PIECE *a, const char *b) {
  36. size_t b_len = strlen(b);
  37. return a->len == b_len && OPENSSL_memcmp(a->data, b, b_len) == 0;
  38. }
  39. // STRING_PIECE_split finds the first occurence of |sep| in |in| and, if found,
  40. // sets |*out_left| and |*out_right| to |in| split before and after it. It
  41. // returns one if |sep| was found and zero otherwise.
  42. static int STRING_PIECE_split(STRING_PIECE *out_left, STRING_PIECE *out_right,
  43. const STRING_PIECE *in, char sep) {
  44. const char *p = (const char *)OPENSSL_memchr(in->data, sep, in->len);
  45. if (p == NULL) {
  46. return 0;
  47. }
  48. // |out_left| or |out_right| may alias |in|, so make a copy.
  49. STRING_PIECE in_copy = *in;
  50. out_left->data = in_copy.data;
  51. out_left->len = p - in_copy.data;
  52. out_right->data = in_copy.data + out_left->len + 1;
  53. out_right->len = in_copy.len - out_left->len - 1;
  54. return 1;
  55. }
  56. // STRING_PIECE_get_delimited reads a |sep|-delimited entry from |s|, writing it
  57. // to |out| and updating |s| to point beyond it. It returns one on success and
  58. // zero if |s| is empty. If |s| is has no copies of |sep| and is non-empty, it
  59. // reads the entire string to |out|.
  60. static int STRING_PIECE_get_delimited(STRING_PIECE *s, STRING_PIECE *out, char sep) {
  61. if (s->len == 0) {
  62. return 0;
  63. }
  64. if (!STRING_PIECE_split(out, s, s, sep)) {
  65. // |s| had no instances of |sep|. Return the entire string.
  66. *out = *s;
  67. s->data += s->len;
  68. s->len = 0;
  69. }
  70. return 1;
  71. }
  72. // STRING_PIECE_trim removes leading and trailing whitespace from |s|.
  73. static void STRING_PIECE_trim(STRING_PIECE *s) {
  74. while (s->len != 0 && (s->data[0] == ' ' || s->data[0] == '\t')) {
  75. s->data++;
  76. s->len--;
  77. }
  78. while (s->len != 0 &&
  79. (s->data[s->len - 1] == ' ' || s->data[s->len - 1] == '\t')) {
  80. s->len--;
  81. }
  82. }
  83. // extract_cpuinfo_field extracts a /proc/cpuinfo field named |field| from
  84. // |in|. If found, it sets |*out| to the value and returns one. Otherwise, it
  85. // returns zero.
  86. static int extract_cpuinfo_field(STRING_PIECE *out, const STRING_PIECE *in,
  87. const char *field) {
  88. // Process |in| one line at a time.
  89. STRING_PIECE remaining = *in, line;
  90. while (STRING_PIECE_get_delimited(&remaining, &line, '\n')) {
  91. STRING_PIECE key, value;
  92. if (!STRING_PIECE_split(&key, &value, &line, ':')) {
  93. continue;
  94. }
  95. STRING_PIECE_trim(&key);
  96. if (STRING_PIECE_equals(&key, field)) {
  97. STRING_PIECE_trim(&value);
  98. *out = value;
  99. return 1;
  100. }
  101. }
  102. return 0;
  103. }
  104. static int cpuinfo_field_equals(const STRING_PIECE *cpuinfo, const char *field,
  105. const char *value) {
  106. STRING_PIECE extracted;
  107. return extract_cpuinfo_field(&extracted, cpuinfo, field) &&
  108. STRING_PIECE_equals(&extracted, value);
  109. }
  110. // has_list_item treats |list| as a space-separated list of items and returns
  111. // one if |item| is contained in |list| and zero otherwise.
  112. static int has_list_item(const STRING_PIECE *list, const char *item) {
  113. STRING_PIECE remaining = *list, feature;
  114. while (STRING_PIECE_get_delimited(&remaining, &feature, ' ')) {
  115. if (STRING_PIECE_equals(&feature, item)) {
  116. return 1;
  117. }
  118. }
  119. return 0;
  120. }
  121. // crypto_get_arm_hwcap_from_cpuinfo returns an equivalent ARM |AT_HWCAP| value
  122. // from |cpuinfo|.
  123. static unsigned long crypto_get_arm_hwcap_from_cpuinfo(
  124. const STRING_PIECE *cpuinfo) {
  125. if (cpuinfo_field_equals(cpuinfo, "CPU architecture", "8")) {
  126. // This is a 32-bit ARM binary running on a 64-bit kernel. NEON is always
  127. // available on ARMv8. Linux omits required features, so reading the
  128. // "Features" line does not work. (For simplicity, use strict equality. We
  129. // assume everything running on future ARM architectures will have a
  130. // working |getauxval|.)
  131. return HWCAP_NEON;
  132. }
  133. STRING_PIECE features;
  134. if (extract_cpuinfo_field(&features, cpuinfo, "Features") &&
  135. has_list_item(&features, "neon")) {
  136. return HWCAP_NEON;
  137. }
  138. return 0;
  139. }
  140. // crypto_get_arm_hwcap2_from_cpuinfo returns an equivalent ARM |AT_HWCAP2|
  141. // value from |cpuinfo|.
  142. static unsigned long crypto_get_arm_hwcap2_from_cpuinfo(
  143. const STRING_PIECE *cpuinfo) {
  144. STRING_PIECE features;
  145. if (!extract_cpuinfo_field(&features, cpuinfo, "Features")) {
  146. return 0;
  147. }
  148. unsigned long ret = 0;
  149. if (has_list_item(&features, "aes")) {
  150. ret |= HWCAP2_AES;
  151. }
  152. if (has_list_item(&features, "pmull")) {
  153. ret |= HWCAP2_PMULL;
  154. }
  155. if (has_list_item(&features, "sha1")) {
  156. ret |= HWCAP2_SHA1;
  157. }
  158. if (has_list_item(&features, "sha2")) {
  159. ret |= HWCAP2_SHA2;
  160. }
  161. return ret;
  162. }
  163. // crypto_cpuinfo_has_broken_neon returns one if |cpuinfo| matches a CPU known
  164. // to have broken NEON unit and zero otherwise. See https://crbug.com/341598.
  165. static int crypto_cpuinfo_has_broken_neon(const STRING_PIECE *cpuinfo) {
  166. return cpuinfo_field_equals(cpuinfo, "CPU implementer", "0x51") &&
  167. cpuinfo_field_equals(cpuinfo, "CPU architecture", "7") &&
  168. cpuinfo_field_equals(cpuinfo, "CPU variant", "0x1") &&
  169. cpuinfo_field_equals(cpuinfo, "CPU part", "0x04d") &&
  170. cpuinfo_field_equals(cpuinfo, "CPU revision", "0");
  171. }
  172. #if defined(__cplusplus)
  173. } // extern C
  174. #endif
  175. #endif // OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H