| // 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 |