#include "base/cpu.h"
#include <stdint.h>
#include <string.h>
#include <string>
#include <string_view>
#include <utility>
#include "base/containers/span.h"
#include "base/containers/span_writer.h"
#include "base/memory/protected_memory.h"
#include "build/build_config.h"
#if defined(ARCH_CPU_ARM_FAMILY) && \
(BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
#include <asm/hwcap.h>
#include <sys/auxv.h>
#include "base/files/file_util.h"
#include "base/numerics/checked_math.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#ifndef HWCAP2_MTE
#define HWCAP2_MTE …
#define HWCAP2_BTI …
#endif
struct ProcCpuInfo {
std::string brand;
uint8_t implementer = 0;
uint32_t part_number = 0;
};
#endif
#if defined(ARCH_CPU_X86_FAMILY)
#if defined(COMPILER_MSVC)
#include <intrin.h>
#include <immintrin.h>
#endif
#endif
namespace base {
#if defined(ARCH_CPU_X86_FAMILY)
namespace internal {
X86ModelInfo ComputeX86FamilyAndModel(const std::string& vendor,
int signature) { … }
}
#endif
CPU::CPU(bool require_branding) { … }
CPU::CPU() : … { … }
CPU::CPU(CPU&&) = default;
namespace {
#if defined(ARCH_CPU_X86_FAMILY)
#if !defined(COMPILER_MSVC)
#if defined(__pic__) && defined(__i386__)
void __cpuidex(int cpu_info[4], int eax, int ecx) {
UNSAFE_BUFFERS(
__asm__ volatile("mov %%ebx, %%edi\n"
"cpuid\n"
"xchg %%edi, %%ebx\n"
: "=a"(cpu_info[0]), "=D"(cpu_info[1]),
"=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(eax), "c"(ecx)));
}
void __cpuid(int cpu_info[4], int info_type) {
__cpuidex(cpu_info, info_type, 0);
}
#else
void __cpuidex(int cpu_info[4], int eax, int ecx) { … }
void __cpuid(int cpu_info[4], int info_type) { … }
#endif
#endif
uint64_t xgetbv(uint32_t xcr) { … }
#endif
#if defined(ARCH_CPU_ARM_FAMILY) && \
(BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
StringPairs::const_iterator FindFirstProcCpuKey(const StringPairs& pairs,
std::string_view key) {
return ranges::find_if(pairs, [key](const StringPairs::value_type& pair) {
return TrimWhitespaceASCII(pair.first, base::TRIM_ALL) == key;
});
}
const ProcCpuInfo& ParseProcCpu() {
static const NoDestructor<ProcCpuInfo> info([]() {
const char kModelNamePrefix[] = "model name";
const char kProcessorPrefix[] = "Processor";
std::string cpuinfo;
ReadFileToString(FilePath("/proc/cpuinfo"), &cpuinfo);
DCHECK(!cpuinfo.empty());
ProcCpuInfo info;
StringPairs pairs;
if (!SplitStringIntoKeyValuePairs(cpuinfo, ':', '\n', &pairs)) {
NOTREACHED();
}
auto model_name = FindFirstProcCpuKey(pairs, kModelNamePrefix);
if (model_name == pairs.end())
model_name = FindFirstProcCpuKey(pairs, kProcessorPrefix);
if (model_name != pairs.end()) {
TrimWhitespaceASCII(model_name->second, TRIM_ALL, &info.brand);
}
auto implementer_string = FindFirstProcCpuKey(pairs, "CPU implementer");
if (implementer_string != pairs.end()) {
uint32_t implementer;
HexStringToUInt(implementer_string->second, &implementer);
if (!CheckedNumeric<uint32_t>(implementer)
.AssignIfValid(&info.implementer)) {
info.implementer = 0;
}
}
auto part_number_string = FindFirstProcCpuKey(pairs, "CPU part");
if (part_number_string != pairs.end())
HexStringToUInt(part_number_string->second, &info.part_number);
return info;
}());
return *info;
}
#endif
DEFINE_PROTECTED_DATA base::ProtectedMemory<CPU> g_cpu_instance;
}
void CPU::Initialize(bool require_branding) { … }
#if defined(ARCH_CPU_X86_FAMILY)
CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const { … }
#endif
const CPU& CPU::GetInstanceNoAllocation() { … }
}