| // Copyright 2018 The BoringSSL Authors | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #ifndef OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H | |
| #define OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H | |
| #include <openssl/base.h> | |
| #include <assert.h> | |
| #include <string_view> | |
| #include "internal.h" | |
| BSSL_NAMESPACE_BEGIN | |
| namespace armcap { | |
| // The cpuinfo parser lives in a header file so it may be accessible from | |
| // cross-platform fuzzers without adding code to those platforms normally. | |
| #define CRYPTO_HWCAP_NEON (1 << 12) | |
| // See /usr/include/asm/hwcap.h on an ARM installation for the source of | |
| // these values. | |
| // We add the prefix "CRYPTO_" to the definitions so as not to collide with | |
| // some versions of glibc (>= 2.41) that expose them through <sys/auxv.h>. | |
| #define CRYPTO_HWCAP2_AES (1 << 0) | |
| #define CRYPTO_HWCAP2_PMULL (1 << 1) | |
| #define CRYPTO_HWCAP2_SHA1 (1 << 2) | |
| #define CRYPTO_HWCAP2_SHA2 (1 << 3) | |
| // SplitStringView finds the first occurrence of `sep` in `in` and, if found, | |
| // sets `*out_left` and `*out_right` to `in` split before and after `sep`, and | |
| // returns true. If not found, it returns false. | |
| inline bool SplitStringView(std::string_view *out_left, | |
| std::string_view *out_right, std::string_view in, | |
| char sep) { | |
| auto pos = in.find(sep); | |
| if (pos == std::string_view::npos) { | |
| return false; | |
| } | |
| *out_left = in.substr(0, pos); | |
| *out_right = in.substr(pos + 1); | |
| return true; | |
| } | |
| // GetDelimited reads a `sep`-delimited entry from `s`, writing it to `out` and | |
| // updating `s` to point beyond it. It returns true on success and false if `s` | |
| // is empty. If `s` has no copies of `sep` and is non-empty, it reads the entire | |
| // string to `out`. | |
| inline bool GetDelimited(std::string_view *s, std::string_view *out, char sep) { | |
| if (s->empty()) { | |
| return false; | |
| } | |
| if (!SplitStringView(out, s, *s, sep)) { | |
| // `s` had no instances of `sep`. Return the entire string. | |
| *out = *s; | |
| *s = std::string_view(); | |
| } | |
| return true; | |
| } | |
| // TrimStringView removes leading and trailing whitespace from `s`. | |
| inline std::string_view TrimStringView(std::string_view s) { | |
| size_t pos = s.find_first_not_of(" \t"); | |
| if (pos == std::string_view::npos) { | |
| return {}; | |
| } | |
| s = s.substr(pos); | |
| pos = s.find_last_not_of(" \t"); | |
| assert(pos != std::string_view::npos); | |
| return s.substr(0, pos + 1); | |
| } | |
| // ExtractCpuinfoField extracts a /proc/cpuinfo field named `field` from `in`. | |
| // If found, it returns the value. Otherwise, it returns the empty string. | |
| inline std::string_view ExtractCpuinfoField(std::string_view in, | |
| std::string_view field) { | |
| // Process `in` one line at a time. | |
| std::string_view line; | |
| while (GetDelimited(&in, &line, '\n')) { | |
| std::string_view key, value; | |
| if (!SplitStringView(&key, &value, line, ':')) { | |
| continue; | |
| } | |
| if (TrimStringView(key) == field) { | |
| return TrimStringView(value); | |
| } | |
| } | |
| return {}; | |
| } | |
| // HasListItem treats `list` as a space-separated list of items and returns | |
| // whether `item` is contained in `list`. | |
| inline bool HasListItem(std::string_view list, std::string_view item) { | |
| std::string_view feature; | |
| while (GetDelimited(&list, &feature, ' ')) { | |
| if (feature == item) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // GetHWCAP2FromCpuinfo returns an equivalent ARM `AT_HWCAP2` value from | |
| // `cpuinfo`. | |
| inline unsigned long GetHWCAP2FromCpuinfo(std::string_view cpuinfo) { | |
| std::string_view features = ExtractCpuinfoField(cpuinfo, "Features"); | |
| unsigned long ret = 0; | |
| if (HasListItem(features, "aes")) { | |
| ret |= CRYPTO_HWCAP2_AES; | |
| } | |
| if (HasListItem(features, "pmull")) { | |
| ret |= CRYPTO_HWCAP2_PMULL; | |
| } | |
| if (HasListItem(features, "sha1")) { | |
| ret |= CRYPTO_HWCAP2_SHA1; | |
| } | |
| if (HasListItem(features, "sha2")) { | |
| ret |= CRYPTO_HWCAP2_SHA2; | |
| } | |
| return ret; | |
| } | |
| } // namespace armcap | |
| BSSL_NAMESPACE_END | |
| #endif // OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H |