tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

cpu.cc (13456B)


      1 // Copyright 2012 The Chromium Authors
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/cpu.h"
      6 
      7 #include <inttypes.h>
      8 #include <limits.h>
      9 #include <stddef.h>
     10 #include <stdint.h>
     11 #include <string.h>
     12 
     13 #include <algorithm>
     14 #include <sstream>
     15 #include <utility>
     16 
     17 #include "base/no_destructor.h"
     18 #include "build/build_config.h"
     19 
     20 #if defined(ARCH_CPU_ARM_FAMILY) && \
     21    (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
     22 #include <asm/hwcap.h>
     23 #include <sys/auxv.h>
     24 
     25 #include "base/files/file_util.h"
     26 #include "base/numerics/checked_math.h"
     27 #include "base/ranges/algorithm.h"
     28 #include "base/strings/string_number_conversions.h"
     29 #include "base/strings/string_split.h"
     30 #include "base/strings/string_util.h"
     31 
     32 // Temporary definitions until a new hwcap.h is pulled in everywhere.
     33 // https://crbug.com/1265965
     34 #ifndef HWCAP2_MTE
     35 #define HWCAP2_MTE (1 << 18)
     36 #define HWCAP2_BTI (1 << 17)
     37 #endif
     38 
     39 struct ProcCpuInfo {
     40  std::string brand;
     41  uint8_t implementer = 0;
     42  uint32_t part_number = 0;
     43 };
     44 #endif
     45 
     46 #if defined(ARCH_CPU_X86_FAMILY)
     47 #if defined(COMPILER_MSVC)
     48 #include <intrin.h>
     49 #include <immintrin.h>  // For _xgetbv()
     50 #endif
     51 #endif
     52 
     53 namespace base {
     54 
     55 #if defined(ARCH_CPU_X86_FAMILY)
     56 namespace internal {
     57 
     58 X86ModelInfo ComputeX86FamilyAndModel(const std::string& vendor,
     59                                      int signature) {
     60  X86ModelInfo results;
     61  results.family = (signature >> 8) & 0xf;
     62  results.model = (signature >> 4) & 0xf;
     63  results.ext_family = 0;
     64  results.ext_model = 0;
     65 
     66  // The "Intel 64 and IA-32 Architectures Developer's Manual: Vol. 2A"
     67  // specifies the Extended Model is defined only when the Base Family is
     68  // 06h or 0Fh.
     69  // The "AMD CPUID Specification" specifies that the Extended Model is
     70  // defined only when Base Family is 0Fh.
     71  // Both manuals define the display model as
     72  // {ExtendedModel[3:0],BaseModel[3:0]} in that case.
     73  if (results.family == 0xf ||
     74      (results.family == 0x6 && vendor == "GenuineIntel")) {
     75    results.ext_model = (signature >> 16) & 0xf;
     76    results.model += results.ext_model << 4;
     77  }
     78  // Both the "Intel 64 and IA-32 Architectures Developer's Manual: Vol. 2A"
     79  // and the "AMD CPUID Specification" specify that the Extended Family is
     80  // defined only when the Base Family is 0Fh.
     81  // Both manuals define the display family as {0000b,BaseFamily[3:0]} +
     82  // ExtendedFamily[7:0] in that case.
     83  if (results.family == 0xf) {
     84    results.ext_family = (signature >> 20) & 0xff;
     85    results.family += results.ext_family;
     86  }
     87 
     88  return results;
     89 }
     90 
     91 }  // namespace internal
     92 #endif  // defined(ARCH_CPU_X86_FAMILY)
     93 
     94 CPU::CPU(bool require_branding) {
     95  Initialize(require_branding);
     96 }
     97 CPU::CPU() : CPU(true) {}
     98 CPU::CPU(CPU&&) = default;
     99 
    100 namespace {
    101 
    102 #if defined(ARCH_CPU_X86_FAMILY)
    103 #if !defined(COMPILER_MSVC)
    104 
    105 #if defined(__pic__) && defined(__i386__)
    106 
    107 void __cpuid(int cpu_info[4], int info_type) {
    108  __asm__ volatile(
    109      "mov %%ebx, %%edi\n"
    110      "cpuid\n"
    111      "xchg %%edi, %%ebx\n"
    112      : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]),
    113        "=d"(cpu_info[3])
    114      : "a"(info_type), "c"(0));
    115 }
    116 
    117 #else
    118 
    119 void __cpuid(int cpu_info[4], int info_type) {
    120  __asm__ volatile("cpuid\n"
    121                   : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]),
    122                     "=d"(cpu_info[3])
    123                   : "a"(info_type), "c"(0));
    124 }
    125 
    126 #endif
    127 #endif  // !defined(COMPILER_MSVC)
    128 
    129 // xgetbv returns the value of an Intel Extended Control Register (XCR).
    130 // Currently only XCR0 is defined by Intel so |xcr| should always be zero.
    131 uint64_t xgetbv(uint32_t xcr) {
    132 #if defined(COMPILER_MSVC)
    133  return _xgetbv(xcr);
    134 #else
    135  uint32_t eax, edx;
    136 
    137  __asm__ volatile (
    138    "xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
    139  return (static_cast<uint64_t>(edx) << 32) | eax;
    140 #endif  // defined(COMPILER_MSVC)
    141 }
    142 
    143 #endif  // ARCH_CPU_X86_FAMILY
    144 
    145 #if defined(ARCH_CPU_ARM_FAMILY) && \
    146    (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
    147 StringPairs::const_iterator FindFirstProcCpuKey(const StringPairs& pairs,
    148                                                StringPiece key) {
    149  return ranges::find_if(pairs, [key](const StringPairs::value_type& pair) {
    150    return TrimWhitespaceASCII(pair.first, base::TRIM_ALL) == key;
    151  });
    152 }
    153 
    154 // Parses information about the ARM processor. Note that depending on the CPU
    155 // package, processor configuration, and/or kernel version, this may only
    156 // report information about the processor on which this thread is running. This
    157 // can happen on heterogeneous-processor SoCs like Snapdragon 808, which has 4
    158 // Cortex-A53 and 2 Cortex-A57. Unfortunately there is not a universally
    159 // reliable way to examine the CPU part information for all cores.
    160 const ProcCpuInfo& ParseProcCpu() {
    161  static const NoDestructor<ProcCpuInfo> info([]() {
    162    // This function finds the value from /proc/cpuinfo under the key "model
    163    // name" or "Processor". "model name" is used in Linux 3.8 and later (3.7
    164    // and later for arm64) and is shown once per CPU. "Processor" is used in
    165    // earler versions and is shown only once at the top of /proc/cpuinfo
    166    // regardless of the number CPUs.
    167    const char kModelNamePrefix[] = "model name";
    168    const char kProcessorPrefix[] = "Processor";
    169 
    170    std::string cpuinfo;
    171    ReadFileToString(FilePath("/proc/cpuinfo"), &cpuinfo);
    172    DCHECK(!cpuinfo.empty());
    173 
    174    ProcCpuInfo info;
    175 
    176    StringPairs pairs;
    177    if (!SplitStringIntoKeyValuePairs(cpuinfo, ':', '\n', &pairs)) {
    178      NOTREACHED();
    179      return info;
    180    }
    181 
    182    auto model_name = FindFirstProcCpuKey(pairs, kModelNamePrefix);
    183    if (model_name == pairs.end())
    184      model_name = FindFirstProcCpuKey(pairs, kProcessorPrefix);
    185    if (model_name != pairs.end()) {
    186      info.brand =
    187          std::string(TrimWhitespaceASCII(model_name->second, TRIM_ALL));
    188    }
    189 
    190    auto implementer_string = FindFirstProcCpuKey(pairs, "CPU implementer");
    191    if (implementer_string != pairs.end()) {
    192      // HexStringToUInt() handles the leading whitespace on the value.
    193      uint32_t implementer;
    194      HexStringToUInt(implementer_string->second, &implementer);
    195      if (!CheckedNumeric<uint32_t>(implementer)
    196               .AssignIfValid(&info.implementer)) {
    197        info.implementer = 0;
    198      }
    199    }
    200 
    201    auto part_number_string = FindFirstProcCpuKey(pairs, "CPU part");
    202    if (part_number_string != pairs.end())
    203      HexStringToUInt(part_number_string->second, &info.part_number);
    204 
    205    return info;
    206  }());
    207 
    208  return *info;
    209 }
    210 #endif  // defined(ARCH_CPU_ARM_FAMILY) && (BUILDFLAG(IS_ANDROID) ||
    211        // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
    212 
    213 }  // namespace
    214 
    215 void CPU::Initialize(bool require_branding) {
    216 #if defined(ARCH_CPU_X86_FAMILY)
    217  int cpu_info[4] = {-1};
    218  // This array is used to temporarily hold the vendor name and then the brand
    219  // name. Thus it has to be big enough for both use cases. There are
    220  // static_asserts below for each of the use cases to make sure this array is
    221  // big enough.
    222  char cpu_string[sizeof(cpu_info) * 3 + 1];
    223 
    224  // __cpuid with an InfoType argument of 0 returns the number of
    225  // valid Ids in CPUInfo[0] and the CPU identification string in
    226  // the other three array elements. The CPU identification string is
    227  // not in linear order. The code below arranges the information
    228  // in a human readable form. The human readable order is CPUInfo[1] |
    229  // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped
    230  // before using memcpy() to copy these three array elements to |cpu_string|.
    231  __cpuid(cpu_info, 0);
    232  int num_ids = cpu_info[0];
    233  std::swap(cpu_info[2], cpu_info[3]);
    234  static constexpr size_t kVendorNameSize = 3 * sizeof(cpu_info[1]);
    235  static_assert(kVendorNameSize < std::size(cpu_string),
    236                "cpu_string too small");
    237  memcpy(cpu_string, &cpu_info[1], kVendorNameSize);
    238  cpu_string[kVendorNameSize] = '\0';
    239  cpu_vendor_ = cpu_string;
    240 
    241  // Interpret CPU feature information.
    242  if (num_ids > 0) {
    243    int cpu_info7[4] = {0};
    244    __cpuid(cpu_info, 1);
    245    if (num_ids >= 7) {
    246      __cpuid(cpu_info7, 7);
    247    }
    248    signature_ = cpu_info[0];
    249    stepping_ = cpu_info[0] & 0xf;
    250    type_ = (cpu_info[0] >> 12) & 0x3;
    251    internal::X86ModelInfo results =
    252        internal::ComputeX86FamilyAndModel(cpu_vendor_, signature_);
    253    family_ = results.family;
    254    model_ = results.model;
    255    ext_family_ = results.ext_family;
    256    ext_model_ = results.ext_model;
    257    has_mmx_ =   (cpu_info[3] & 0x00800000) != 0;
    258    has_sse_ =   (cpu_info[3] & 0x02000000) != 0;
    259    has_sse2_ =  (cpu_info[3] & 0x04000000) != 0;
    260    has_sse3_ =  (cpu_info[2] & 0x00000001) != 0;
    261    has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
    262    has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
    263    has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
    264    has_popcnt_ = (cpu_info[2] & 0x00800000) != 0;
    265 
    266    // "Hypervisor Present Bit: Bit 31 of ECX of CPUID leaf 0x1."
    267    // See https://lwn.net/Articles/301888/
    268    // This is checking for any hypervisor. Hypervisors may choose not to
    269    // announce themselves. Hypervisors trap CPUID and sometimes return
    270    // different results to underlying hardware.
    271    is_running_in_vm_ = (static_cast<uint32_t>(cpu_info[2]) & 0x80000000) != 0;
    272 
    273    // AVX instructions will generate an illegal instruction exception unless
    274    //   a) they are supported by the CPU,
    275    //   b) XSAVE is supported by the CPU and
    276    //   c) XSAVE is enabled by the kernel.
    277    // See http://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled
    278    //
    279    // In addition, we have observed some crashes with the xgetbv instruction
    280    // even after following Intel's example code. (See crbug.com/375968.)
    281    // Because of that, we also test the XSAVE bit because its description in
    282    // the CPUID documentation suggests that it signals xgetbv support.
    283    has_avx_ =
    284        (cpu_info[2] & 0x10000000) != 0 &&
    285        (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
    286        (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
    287        (xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */;
    288    has_aesni_ = (cpu_info[2] & 0x02000000) != 0;
    289    has_fma3_ = (cpu_info[2] & 0x00001000) != 0;
    290    has_avx2_ = has_avx_ && (cpu_info7[1] & 0x00000020) != 0;
    291 
    292    has_pku_ = (cpu_info7[2] & 0x00000010) != 0;
    293  }
    294 
    295  // Get the brand string of the cpu.
    296  __cpuid(cpu_info, static_cast<int>(0x80000000));
    297  const uint32_t max_parameter = static_cast<uint32_t>(cpu_info[0]);
    298 
    299  static constexpr uint32_t kParameterStart = 0x80000002;
    300  static constexpr uint32_t kParameterEnd = 0x80000004;
    301  static constexpr uint32_t kParameterSize =
    302      kParameterEnd - kParameterStart + 1;
    303  static_assert(kParameterSize * sizeof(cpu_info) + 1 == std::size(cpu_string),
    304                "cpu_string has wrong size");
    305 
    306  if (max_parameter >= kParameterEnd) {
    307    size_t i = 0;
    308    for (uint32_t parameter = kParameterStart; parameter <= kParameterEnd;
    309         ++parameter) {
    310      __cpuid(cpu_info, static_cast<int>(parameter));
    311      memcpy(&cpu_string[i], cpu_info, sizeof(cpu_info));
    312      i += sizeof(cpu_info);
    313    }
    314    cpu_string[i] = '\0';
    315    cpu_brand_ = cpu_string;
    316  }
    317 
    318  static constexpr uint32_t kParameterContainingNonStopTimeStampCounter =
    319      0x80000007;
    320  if (max_parameter >= kParameterContainingNonStopTimeStampCounter) {
    321    __cpuid(cpu_info,
    322            static_cast<int>(kParameterContainingNonStopTimeStampCounter));
    323    has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0;
    324  }
    325 
    326  if (!has_non_stop_time_stamp_counter_ && is_running_in_vm_) {
    327    int cpu_info_hv[4] = {};
    328    __cpuid(cpu_info_hv, 0x40000000);
    329    if (cpu_info_hv[1] == 0x7263694D &&  // Micr
    330        cpu_info_hv[2] == 0x666F736F &&  // osof
    331        cpu_info_hv[3] == 0x76482074) {  // t Hv
    332      // If CPUID says we have a variant TSC and a hypervisor has identified
    333      // itself and the hypervisor says it is Microsoft Hyper-V, then treat
    334      // TSC as invariant.
    335      //
    336      // Microsoft Hyper-V hypervisor reports variant TSC as there are some
    337      // scenarios (eg. VM live migration) where the TSC is variant, but for
    338      // our purposes we can treat it as invariant.
    339      has_non_stop_time_stamp_counter_ = true;
    340    }
    341  }
    342 #elif defined(ARCH_CPU_ARM_FAMILY)
    343 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
    344  if (require_branding) {
    345    const ProcCpuInfo& info = ParseProcCpu();
    346    cpu_brand_ = info.brand;
    347    implementer_ = info.implementer;
    348    part_number_ = info.part_number;
    349  }
    350 
    351 #if defined(ARCH_CPU_ARM64)
    352  // Check for Armv8.5-A BTI/MTE support, exposed via HWCAP2
    353  unsigned long hwcap2 = getauxval(AT_HWCAP2);
    354  has_mte_ = hwcap2 & HWCAP2_MTE;
    355  has_bti_ = hwcap2 & HWCAP2_BTI;
    356 #endif
    357 
    358 #elif BUILDFLAG(IS_WIN)
    359  // Windows makes high-resolution thread timing information available in
    360  // user-space.
    361  has_non_stop_time_stamp_counter_ = true;
    362 #endif
    363 #endif
    364 }
    365 
    366 #if defined(ARCH_CPU_X86_FAMILY)
    367 CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
    368  if (has_avx2()) return AVX2;
    369  if (has_fma3()) return FMA3;
    370  if (has_avx()) return AVX;
    371  if (has_sse42()) return SSE42;
    372  if (has_sse41()) return SSE41;
    373  if (has_ssse3()) return SSSE3;
    374  if (has_sse3()) return SSE3;
    375  if (has_sse2()) return SSE2;
    376  if (has_sse()) return SSE;
    377  return PENTIUM;
    378 }
    379 #endif
    380 
    381 const CPU& CPU::GetInstanceNoAllocation() {
    382  static const base::NoDestructor<const CPU> cpu(CPU(false));
    383 
    384  return *cpu;
    385 }
    386 
    387 }  // namespace base