cpu-arm-linux.h
Go to the documentation of this file.
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 
15 #ifndef OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H
16 #define OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H
17 
18 #include <openssl/base.h>
19 
20 #include <string.h>
21 
22 #include "internal.h"
23 
24 #if defined(__cplusplus)
25 extern "C" {
26 #endif
27 
28 
29 // The cpuinfo parser lives in a header file so it may be accessible from
30 // cross-platform fuzzers without adding code to those platforms normally.
31 
32 #define HWCAP_NEON (1 << 12)
33 
34 // See /usr/include/asm/hwcap.h on an ARM installation for the source of
35 // these values.
36 #define HWCAP2_AES (1 << 0)
37 #define HWCAP2_PMULL (1 << 1)
38 #define HWCAP2_SHA1 (1 << 2)
39 #define HWCAP2_SHA2 (1 << 3)
40 
41 typedef struct {
42  const char *data;
43  size_t len;
44 } STRING_PIECE;
45 
46 static int STRING_PIECE_equals(const STRING_PIECE *a, const char *b) {
47  size_t b_len = strlen(b);
48  return a->len == b_len && OPENSSL_memcmp(a->data, b, b_len) == 0;
49 }
50 
51 // STRING_PIECE_split finds the first occurence of |sep| in |in| and, if found,
52 // sets |*out_left| and |*out_right| to |in| split before and after it. It
53 // returns one if |sep| was found and zero otherwise.
54 static int STRING_PIECE_split(STRING_PIECE *out_left, STRING_PIECE *out_right,
55  const STRING_PIECE *in, char sep) {
56  const char *p = (const char *)OPENSSL_memchr(in->data, sep, in->len);
57  if (p == NULL) {
58  return 0;
59  }
60  // |out_left| or |out_right| may alias |in|, so make a copy.
61  STRING_PIECE in_copy = *in;
62  out_left->data = in_copy.data;
63  out_left->len = p - in_copy.data;
64  out_right->data = in_copy.data + out_left->len + 1;
65  out_right->len = in_copy.len - out_left->len - 1;
66  return 1;
67 }
68 
69 // STRING_PIECE_get_delimited reads a |sep|-delimited entry from |s|, writing it
70 // to |out| and updating |s| to point beyond it. It returns one on success and
71 // zero if |s| is empty. If |s| is has no copies of |sep| and is non-empty, it
72 // reads the entire string to |out|.
74  if (s->len == 0) {
75  return 0;
76  }
77  if (!STRING_PIECE_split(out, s, s, sep)) {
78  // |s| had no instances of |sep|. Return the entire string.
79  *out = *s;
80  s->data += s->len;
81  s->len = 0;
82  }
83  return 1;
84 }
85 
86 // STRING_PIECE_trim removes leading and trailing whitespace from |s|.
88  while (s->len != 0 && (s->data[0] == ' ' || s->data[0] == '\t')) {
89  s->data++;
90  s->len--;
91  }
92  while (s->len != 0 &&
93  (s->data[s->len - 1] == ' ' || s->data[s->len - 1] == '\t')) {
94  s->len--;
95  }
96 }
97 
98 // extract_cpuinfo_field extracts a /proc/cpuinfo field named |field| from
99 // |in|. If found, it sets |*out| to the value and returns one. Otherwise, it
100 // returns zero.
102  const char *field) {
103  // Process |in| one line at a time.
104  STRING_PIECE remaining = *in, line;
105  while (STRING_PIECE_get_delimited(&remaining, &line, '\n')) {
107  if (!STRING_PIECE_split(&key, &value, &line, ':')) {
108  continue;
109  }
111  if (STRING_PIECE_equals(&key, field)) {
113  *out = value;
114  return 1;
115  }
116  }
117 
118  return 0;
119 }
120 
121 static int cpuinfo_field_equals(const STRING_PIECE *cpuinfo, const char *field,
122  const char *value) {
123  STRING_PIECE extracted;
124  return extract_cpuinfo_field(&extracted, cpuinfo, field) &&
125  STRING_PIECE_equals(&extracted, value);
126 }
127 
128 // has_list_item treats |list| as a space-separated list of items and returns
129 // one if |item| is contained in |list| and zero otherwise.
130 static int has_list_item(const STRING_PIECE *list, const char *item) {
131  STRING_PIECE remaining = *list, feature;
132  while (STRING_PIECE_get_delimited(&remaining, &feature, ' ')) {
133  if (STRING_PIECE_equals(&feature, item)) {
134  return 1;
135  }
136  }
137  return 0;
138 }
139 
140 // crypto_get_arm_hwcap_from_cpuinfo returns an equivalent ARM |AT_HWCAP| value
141 // from |cpuinfo|.
143  const STRING_PIECE *cpuinfo) {
144  if (cpuinfo_field_equals(cpuinfo, "CPU architecture", "8")) {
145  // This is a 32-bit ARM binary running on a 64-bit kernel. NEON is always
146  // available on ARMv8. Linux omits required features, so reading the
147  // "Features" line does not work. (For simplicity, use strict equality. We
148  // assume everything running on future ARM architectures will have a
149  // working |getauxval|.)
150  return HWCAP_NEON;
151  }
152 
153  STRING_PIECE features;
154  if (extract_cpuinfo_field(&features, cpuinfo, "Features") &&
155  has_list_item(&features, "neon")) {
156  return HWCAP_NEON;
157  }
158  return 0;
159 }
160 
161 // crypto_get_arm_hwcap2_from_cpuinfo returns an equivalent ARM |AT_HWCAP2|
162 // value from |cpuinfo|.
164  const STRING_PIECE *cpuinfo) {
165  STRING_PIECE features;
166  if (!extract_cpuinfo_field(&features, cpuinfo, "Features")) {
167  return 0;
168  }
169 
170  unsigned long ret = 0;
171  if (has_list_item(&features, "aes")) {
172  ret |= HWCAP2_AES;
173  }
174  if (has_list_item(&features, "pmull")) {
175  ret |= HWCAP2_PMULL;
176  }
177  if (has_list_item(&features, "sha1")) {
178  ret |= HWCAP2_SHA1;
179  }
180  if (has_list_item(&features, "sha2")) {
181  ret |= HWCAP2_SHA2;
182  }
183  return ret;
184 }
185 
186 // crypto_cpuinfo_has_broken_neon returns one if |cpuinfo| matches a CPU known
187 // to have broken NEON unit and zero otherwise. See https://crbug.com/341598.
188 static int crypto_cpuinfo_has_broken_neon(const STRING_PIECE *cpuinfo) {
189  return cpuinfo_field_equals(cpuinfo, "CPU implementer", "0x51") &&
190  cpuinfo_field_equals(cpuinfo, "CPU architecture", "7") &&
191  cpuinfo_field_equals(cpuinfo, "CPU variant", "0x1") &&
192  cpuinfo_field_equals(cpuinfo, "CPU part", "0x04d") &&
193  cpuinfo_field_equals(cpuinfo, "CPU revision", "0");
194 }
195 
196 
197 #if defined(__cplusplus)
198 } // extern C
199 #endif
200 
201 #endif // OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H
STRING_PIECE_get_delimited
static int STRING_PIECE_get_delimited(STRING_PIECE *s, STRING_PIECE *out, char sep)
Definition: cpu-arm-linux.h:73
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
HWCAP2_SHA1
#define HWCAP2_SHA1
Definition: cpu-arm-linux.h:38
HWCAP2_AES
#define HWCAP2_AES
Definition: cpu-arm-linux.h:36
OPENSSL_memcmp
static int OPENSSL_memcmp(const void *s1, const void *s2, size_t n)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:811
internal.h
crypto_cpuinfo_has_broken_neon
static int crypto_cpuinfo_has_broken_neon(const STRING_PIECE *cpuinfo)
Definition: cpu-arm-linux.h:188
string.h
crypto_get_arm_hwcap_from_cpuinfo
static unsigned long crypto_get_arm_hwcap_from_cpuinfo(const STRING_PIECE *cpuinfo)
Definition: cpu-arm-linux.h:142
OPENSSL_memchr
static void * OPENSSL_memchr(const void *s, int c, size_t n)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:801
HWCAP2_PMULL
#define HWCAP2_PMULL
Definition: cpu-arm-linux.h:37
HWCAP_NEON
#define HWCAP_NEON
Definition: cpu-arm-linux.h:32
STRING_PIECE
Definition: cpu-arm-linux.h:41
extract_cpuinfo_field
static int extract_cpuinfo_field(STRING_PIECE *out, const STRING_PIECE *in, const char *field)
Definition: cpu-arm-linux.h:101
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
xds_manager.p
p
Definition: xds_manager.py:60
STRING_PIECE_split
static int STRING_PIECE_split(STRING_PIECE *out_left, STRING_PIECE *out_right, const STRING_PIECE *in, char sep)
Definition: cpu-arm-linux.h:54
base.h
in
const char * in
Definition: third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc:391
cpuinfo_field_equals
static int cpuinfo_field_equals(const STRING_PIECE *cpuinfo, const char *field, const char *value)
Definition: cpu-arm-linux.h:121
crypto_get_arm_hwcap2_from_cpuinfo
static unsigned long crypto_get_arm_hwcap2_from_cpuinfo(const STRING_PIECE *cpuinfo)
Definition: cpu-arm-linux.h:163
text_format_test_wrapper.sep
sep
Definition: text_format_test_wrapper.py:34
STRING_PIECE::len
size_t len
Definition: cpu-arm-linux.h:43
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
value
const char * value
Definition: hpack_parser_table.cc:165
has_list_item
static int has_list_item(const STRING_PIECE *list, const char *item)
Definition: cpu-arm-linux.h:130
field
const FieldDescriptor * field
Definition: bloaty/third_party/protobuf/src/google/protobuf/compiler/parser_unittest.cc:2692
key
const char * key
Definition: hpack_parser_table.cc:164
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
regen-readme.line
line
Definition: regen-readme.py:30
HWCAP2_SHA2
#define HWCAP2_SHA2
Definition: cpu-arm-linux.h:39
STRING_PIECE::data
const char * data
Definition: cpu-arm-linux.h:42
STRING_PIECE_trim
static void STRING_PIECE_trim(STRING_PIECE *s)
Definition: cpu-arm-linux.h:87
STRING_PIECE_equals
static int STRING_PIECE_equals(const STRING_PIECE *a, const char *b)
Definition: cpu-arm-linux.h:46


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:58:59