diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-08 08:45:24 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-08 08:47:28 +0000 |
commit | c37c1a8c26193f479398c2fdd7c3bcecb8455705 (patch) | |
tree | 1ad5e40316d66968a6a4921e906049ce68a8ce39 /base/cpu.cc | |
parent | 3e0c8ca428f41a1781739062e0a4fc6928c70523 (diff) | |
download | chromium_src-c37c1a8c26193f479398c2fdd7c3bcecb8455705.zip chromium_src-c37c1a8c26193f479398c2fdd7c3bcecb8455705.tar.gz chromium_src-c37c1a8c26193f479398c2fdd7c3bcecb8455705.tar.bz2 |
Disable Poly1305 code only on bad chips.
This change detects buggy ARM chips and disables the Poly1305 code only on
those chips.
BUG=341598
Review URL: https://codereview.chromium.org/442863003
Cr-Commit-Position: refs/heads/master@{#288267}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288267 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/cpu.cc')
-rw-r--r-- | base/cpu.cc | 113 |
1 files changed, 82 insertions, 31 deletions
diff --git a/base/cpu.cc b/base/cpu.cc index dcba3b6..a6a6128 100644 --- a/base/cpu.cc +++ b/base/cpu.cc @@ -4,11 +4,13 @@ #include "base/cpu.h" +#include <stdlib.h> #include <string.h> #include <algorithm> #include "base/basictypes.h" +#include "base/strings/string_piece.h" #include "build/build_config.h" #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) @@ -44,6 +46,7 @@ CPU::CPU() has_avx_hardware_(false), has_aesni_(false), has_non_stop_time_stamp_counter_(false), + has_broken_neon_(false), cpu_vendor_("unknown") { Initialize(); } @@ -90,52 +93,99 @@ uint64 _xgetbv(uint32 xcr) { #endif // ARCH_CPU_X86_FAMILY #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) +class LazyCpuInfoValue { + public: + LazyCpuInfoValue() : has_broken_neon_(false) { + // This function finds the value from /proc/cpuinfo under the key "model + // name" or "Processor". "model name" is used in Linux 3.8 and later (3.7 + // and later for arm64) and is shown once per CPU. "Processor" is used in + // earler versions and is shown only once at the top of /proc/cpuinfo + // regardless of the number CPUs. + const char kModelNamePrefix[] = "model name\t: "; + const char kProcessorPrefix[] = "Processor\t: "; + + // This function also calculates whether we believe that this CPU has a + // broken NEON unit based on these fields from cpuinfo: + unsigned implementer = 0, architecture = 0, variant = 0, part = 0, + revision = 0; + const struct { + const char key[17]; + unsigned *result; + } kUnsignedValues[] = { + {"CPU implementer", &implementer}, + {"CPU architecture", &architecture}, + {"CPU variant", &variant}, + {"CPU part", &part}, + {"CPU revision", &revision}, + }; + + std::string contents; + ReadFileToString(FilePath("/proc/cpuinfo"), &contents); + DCHECK(!contents.empty()); + if (contents.empty()) { + return; + } -// Returns the string found in /proc/cpuinfo under the key "model name" or -// "Processor". "model name" is used in Linux 3.8 and later (3.7 and later for -// arm64) and is shown once per CPU. "Processor" is used in earler versions and -// is shown only once at the top of /proc/cpuinfo regardless of the number CPUs. -std::string ParseCpuInfo() { - const char kModelNamePrefix[] = "model name\t: "; - const char kProcessorPrefix[] = "Processor\t: "; - std::string contents; - ReadFileToString(FilePath("/proc/cpuinfo"), &contents); - DCHECK(!contents.empty()); - std::string cpu_brand; - if (!contents.empty()) { std::istringstream iss(contents); std::string line; while (std::getline(iss, line)) { - if (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0) { - cpu_brand.assign(line.substr(strlen(kModelNamePrefix))); - break; + if (brand_.empty() && + (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0 || + line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0)) { + brand_.assign(line.substr(strlen(kModelNamePrefix))); } - if (line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0) { - cpu_brand.assign(line.substr(strlen(kProcessorPrefix))); - break; + + for (size_t i = 0; i < arraysize(kUnsignedValues); i++) { + const char *key = kUnsignedValues[i].key; + const size_t len = strlen(key); + + if (line.compare(0, len, key) == 0 && + line.size() >= len + 1 && + (line[len] == '\t' || line[len] == ' ' || line[len] == ':')) { + size_t colon_pos = line.find(':', len); + if (colon_pos == std::string::npos) { + continue; + } + + const StringPiece line_sp(line); + StringPiece value_sp = line_sp.substr(colon_pos + 1); + while (!value_sp.empty() && + (value_sp[0] == ' ' || value_sp[0] == '\t')) { + value_sp = value_sp.substr(1); + } + + // The string may have leading "0x" or not, so we use strtoul to + // handle that. + char *endptr; + std::string value(value_sp.as_string()); + unsigned long int result = strtoul(value.c_str(), &endptr, 0); + if (*endptr == 0 && result <= UINT_MAX) { + *kUnsignedValues[i].result = result; + } + } } } + + has_broken_neon_ = + implementer == 0x51 && + architecture == 7 && + variant == 1 && + part == 0x4d && + revision == 0; } - return cpu_brand; -} -class LazyCpuInfoValue { - public: - LazyCpuInfoValue() : value_(ParseCpuInfo()) {} - const std::string& value() { return value_; } + const std::string& brand() const { return brand_; } + bool has_broken_neon() const { return has_broken_neon_; } private: - const std::string value_; + std::string brand_; + bool has_broken_neon_; DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue); }; -base::LazyInstance<LazyCpuInfoValue> g_lazy_cpu_brand = +base::LazyInstance<LazyCpuInfoValue>::Leaky g_lazy_cpuinfo = LAZY_INSTANCE_INITIALIZER; -const std::string& CpuBrandInfo() { - return g_lazy_cpu_brand.Get().value(); -} - #endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || // defined(OS_LINUX)) @@ -219,7 +269,8 @@ void CPU::Initialize() { has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0; } #elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) - cpu_brand_.assign(CpuBrandInfo()); + cpu_brand_.assign(g_lazy_cpuinfo.Get().brand()); + has_broken_neon_ = g_lazy_cpuinfo.Get().has_broken_neon(); #endif } |