Coverage Report

Created: 2026-04-15 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/cpu_arm_linux.h
Line
Count
Source
1
// Copyright 2018 The BoringSSL Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
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 <assert.h>
21
22
#include <string_view>
23
24
#include "internal.h"
25
26
27
BSSL_NAMESPACE_BEGIN
28
namespace armcap {
29
30
// The cpuinfo parser lives in a header file so it may be accessible from
31
// cross-platform fuzzers without adding code to those platforms normally.
32
33
#define CRYPTO_HWCAP_NEON (1 << 12)
34
35
// See /usr/include/asm/hwcap.h on an ARM installation for the source of
36
// these values.
37
// We add the prefix "CRYPTO_" to the definitions so as not to collide with
38
// some versions of glibc (>= 2.41) that expose them through <sys/auxv.h>.
39
1
#define CRYPTO_HWCAP2_AES (1 << 0)
40
3
#define CRYPTO_HWCAP2_PMULL (1 << 1)
41
4
#define CRYPTO_HWCAP2_SHA1 (1 << 2)
42
4
#define CRYPTO_HWCAP2_SHA2 (1 << 3)
43
44
// SplitStringView finds the first occurrence of |sep| in |in| and, if found,
45
// sets |*out_left| and |*out_right| to |in| split before and after |sep|, and
46
// returns true. If not found, it returns false.
47
inline bool SplitStringView(std::string_view *out_left,
48
                            std::string_view *out_right, std::string_view in,
49
2.01M
                            char sep) {
50
2.01M
  auto pos = in.find(sep);
51
2.01M
  if (pos == std::string_view::npos) {
52
253k
    return false;
53
253k
  }
54
1.75M
  *out_left = in.substr(0, pos);
55
1.75M
  *out_right = in.substr(pos + 1);
56
1.75M
  return true;
57
2.01M
}
58
59
// GetDelimited reads a |sep|-delimited entry from |s|, writing it to |out| and
60
// updating |s| to point beyond it. It returns true on success and false if |s|
61
// is empty. If |s| has no copies of |sep| and is non-empty, it reads the entire
62
// string to |out|.
63
1.75M
inline bool GetDelimited(std::string_view *s, std::string_view *out, char sep) {
64
1.75M
  if (s->empty()) {
65
2.80k
    return false;
66
2.80k
  }
67
1.75M
  if (!SplitStringView(out, s, *s, sep)) {
68
    // |s| had no instances of |sep|. Return the entire string.
69
1.78k
    *out = *s;
70
1.78k
    *s = std::string_view();
71
1.78k
  }
72
1.75M
  return true;
73
1.75M
}
74
75
// TrimStringView removes leading and trailing whitespace from |s|.
76
6.64k
inline std::string_view TrimStringView(std::string_view s) {
77
6.64k
  size_t pos = s.find_first_not_of(" \t");
78
6.64k
  if (pos == std::string_view::npos) {
79
2.43k
    return {};
80
2.43k
  }
81
4.21k
  s = s.substr(pos);
82
4.21k
  pos = s.find_last_not_of(" \t");
83
4.21k
  assert(pos != std::string_view::npos);
84
4.21k
  return s.substr(0, pos + 1);
85
4.21k
}
86
87
// ExtractCpuinfoField extracts a /proc/cpuinfo field named |field| from |in|.
88
// If found, it returns the value. Otherwise, it returns the empty string.
89
inline std::string_view ExtractCpuinfoField(std::string_view in,
90
624
                                            std::string_view field) {
91
  // Process |in| one line at a time.
92
624
  std::string_view line;
93
258k
  while (GetDelimited(&in, &line, '\n')) {
94
258k
    std::string_view key, value;
95
258k
    if (!SplitStringView(&key, &value, line, ':')) {
96
251k
      continue;
97
251k
    }
98
6.34k
    if (TrimStringView(key) == field) {
99
308
      return TrimStringView(value);
100
308
    }
101
6.34k
  }
102
103
316
  return {};
104
624
}
105
106
// HasListItem treats |list| as a space-separated list of items and returns
107
// whether |item| is contained in |list|.
108
2.49k
inline bool HasListItem(std::string_view list, std::string_view item) {
109
2.49k
  std::string_view feature;
110
1.49M
  while (GetDelimited(&list, &feature, ' ')) {
111
1.49M
    if (feature == item) {
112
12
      return true;
113
12
    }
114
1.49M
  }
115
2.48k
  return false;
116
2.49k
}
117
118
// GetHWCAP2FromCpuinfo returns an equivalent ARM |AT_HWCAP2| value from
119
// |cpuinfo|.
120
624
inline unsigned long GetHWCAP2FromCpuinfo(std::string_view cpuinfo) {
121
624
  std::string_view features = ExtractCpuinfoField(cpuinfo, "Features");
122
624
  unsigned long ret = 0;
123
624
  if (HasListItem(features, "aes")) {
124
1
    ret |= CRYPTO_HWCAP2_AES;
125
1
  }
126
624
  if (HasListItem(features, "pmull")) {
127
3
    ret |= CRYPTO_HWCAP2_PMULL;
128
3
  }
129
624
  if (HasListItem(features, "sha1")) {
130
4
    ret |= CRYPTO_HWCAP2_SHA1;
131
4
  }
132
624
  if (HasListItem(features, "sha2")) {
133
4
    ret |= CRYPTO_HWCAP2_SHA2;
134
4
  }
135
624
  return ret;
136
624
}
137
138
}  // namespace armcap
139
BSSL_NAMESPACE_END
140
141
#endif  // OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H