Coverage Report

Created: 2026-08-08 07:14

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
4
#define CRYPTO_HWCAP2_PMULL (1 << 1)
41
3
#define CRYPTO_HWCAP2_SHA1 (1 << 2)
42
5
#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
1.11M
                            char sep) {
50
1.11M
  auto pos = in.find(sep);
51
1.11M
  if (pos == std::string_view::npos) {
52
497k
    return false;
53
497k
  }
54
615k
  *out_left = in.substr(0, pos);
55
615k
  *out_right = in.substr(pos + 1);
56
615k
  return true;
57
1.11M
}
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
611k
inline bool GetDelimited(std::string_view *s, std::string_view *out, char sep) {
64
611k
  if (s->empty()) {
65
2.79k
    return false;
66
2.79k
  }
67
608k
  if (!SplitStringView(out, s, *s, sep)) {
68
    // `s` had no instances of `sep`. Return the entire string.
69
1.79k
    *out = *s;
70
1.79k
    *s = std::string_view();
71
1.79k
  }
72
608k
  return true;
73
611k
}
74
75
// TrimStringView removes leading and trailing whitespace from `s`.
76
8.85k
inline std::string_view TrimStringView(std::string_view s) {
77
8.85k
  size_t pos = s.find_first_not_of(" \t");
78
8.85k
  if (pos == std::string_view::npos) {
79
2.83k
    return {};
80
2.83k
  }
81
6.01k
  s = s.substr(pos);
82
6.01k
  pos = s.find_last_not_of(" \t");
83
6.01k
  assert(pos != std::string_view::npos);
84
6.01k
  return s.substr(0, pos + 1);
85
6.01k
}
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
504k
  while (GetDelimited(&in, &line, '\n')) {
94
504k
    std::string_view key, value;
95
504k
    if (!SplitStringView(&key, &value, line, ':')) {
96
495k
      continue;
97
495k
    }
98
8.54k
    if (TrimStringView(key) == field) {
99
312
      return TrimStringView(value);
100
312
    }
101
8.54k
  }
102
103
312
  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
106k
  while (GetDelimited(&list, &feature, ' ')) {
111
104k
    if (feature == item) {
112
13
      return true;
113
13
    }
114
104k
  }
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
4
    ret |= CRYPTO_HWCAP2_PMULL;
128
4
  }
129
624
  if (HasListItem(features, "sha1")) {
130
3
    ret |= CRYPTO_HWCAP2_SHA1;
131
3
  }
132
624
  if (HasListItem(features, "sha2")) {
133
5
    ret |= CRYPTO_HWCAP2_SHA2;
134
5
  }
135
624
  return ret;
136
624
}
137
138
}  // namespace armcap
139
BSSL_NAMESPACE_END
140
141
#endif  // OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H