Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 7a0539159d323f2c26f8b5551fb8638878ab2c56 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2012 The Chromium Authors
[email protected]de8d26672008-09-25 22:08:442// 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"
[email protected]7e6d42b2011-02-16 18:51:586
avi9b6f42932015-12-26 22:15:147#include <stdint.h>
[email protected]d1811bc2012-03-31 07:08:538#include <string.h>
9
André Kempe1994caac2024-04-05 15:01:3910#include <string>
Helmut Januschka000f5ac2024-04-02 16:33:4011#include <string_view>
Lei Zhang49c4b2a2017-11-03 21:34:2312#include <utility>
[email protected]595d1592012-10-04 21:05:2313
Jan Keitel6c981202024-08-06 09:02:4514#include "base/containers/span.h"
15#include "base/containers/span_writer.h"
André Kempe1994caac2024-04-05 15:01:3916#include "base/memory/protected_memory.h"
Xiaohan Wang38e4ebb2022-01-19 06:57:4317#include "build/build_config.h"
[email protected]d1811bc2012-03-31 07:08:5318
Sean McAllister39b8d342020-08-25 09:08:3219#if defined(ARCH_CPU_ARM_FAMILY) && \
Xiaohan Wang38e4ebb2022-01-19 06:57:4320 (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
Richard Townsend8cb7ba0b2020-11-26 23:23:2221#include <asm/hwcap.h>
22#include <sys/auxv.h>
Lei Zhang2c857be72022-11-03 16:16:4323
Peter Kasting025a94252025-01-29 21:28:3724#include <algorithm>
25
Robert Sesekfd71c382021-01-14 18:40:5226#include "base/numerics/checked_math.h"
Lei Zhang2c857be72022-11-03 16:16:4327#include "base/strings/string_number_conversions.h"
Robert Sesekfd71c382021-01-14 18:40:5228#include "base/strings/string_split.h"
29#include "base/strings/string_util.h"
30
André Kempe13954212022-01-28 17:27:0831// Temporary definitions until a new hwcap.h is pulled in everywhere.
32// https://crbug.com/1265965
33#ifndef HWCAP2_MTE
Andrew Grievecbfe6fb2021-11-02 16:47:3834#define HWCAP2_MTE (1 << 18)
35#define HWCAP2_BTI (1 << 17)
André Kempe13954212022-01-28 17:27:0836#endif
[email protected]3a23f63c2014-04-28 15:33:2637#endif
38
[email protected]7e6d42b2011-02-16 18:51:5839#if defined(ARCH_CPU_X86_FAMILY)
Thiago Farinaba7d2a422017-06-17 00:18:4940#if defined(COMPILER_MSVC)
[email protected]f3d445e2013-11-22 18:35:0341#include <immintrin.h> // For _xgetbv()
Peter Kasting134ef9af2024-12-28 02:30:0942#include <intrin.h>
[email protected]7e6d42b2011-02-16 18:51:5843#endif
44#endif
45
[email protected]de8d26672008-09-25 22:08:4446namespace base {
47
Gabriel Marin8fdd7772019-08-17 00:28:0948#if defined(ARCH_CPU_X86_FAMILY)
49namespace internal {
50
Lei Zhang1b1116c52021-05-14 22:54:3851X86ModelInfo ComputeX86FamilyAndModel(const std::string& vendor,
52 int signature) {
53 X86ModelInfo results;
54 results.family = (signature >> 8) & 0xf;
55 results.model = (signature >> 4) & 0xf;
56 results.ext_family = 0;
57 results.ext_model = 0;
Gabriel Marin8fdd7772019-08-17 00:28:0958
59 // The "Intel 64 and IA-32 Architectures Developer's Manual: Vol. 2A"
60 // specifies the Extended Model is defined only when the Base Family is
61 // 06h or 0Fh.
62 // The "AMD CPUID Specification" specifies that the Extended Model is
63 // defined only when Base Family is 0Fh.
64 // Both manuals define the display model as
65 // {ExtendedModel[3:0],BaseModel[3:0]} in that case.
Lei Zhang1b1116c52021-05-14 22:54:3866 if (results.family == 0xf ||
67 (results.family == 0x6 && vendor == "GenuineIntel")) {
68 results.ext_model = (signature >> 16) & 0xf;
69 results.model += results.ext_model << 4;
Gabriel Marin8fdd7772019-08-17 00:28:0970 }
71 // Both the "Intel 64 and IA-32 Architectures Developer's Manual: Vol. 2A"
72 // and the "AMD CPUID Specification" specify that the Extended Family is
73 // defined only when the Base Family is 0Fh.
74 // Both manuals define the display family as {0000b,BaseFamily[3:0]} +
75 // ExtendedFamily[7:0] in that case.
Lei Zhang1b1116c52021-05-14 22:54:3876 if (results.family == 0xf) {
77 results.ext_family = (signature >> 20) & 0xff;
78 results.family += results.ext_family;
Gabriel Marin8fdd7772019-08-17 00:28:0979 }
80
Lei Zhang1b1116c52021-05-14 22:54:3881 return results;
Gabriel Marin8fdd7772019-08-17 00:28:0982}
83
84} // namespace internal
85#endif // defined(ARCH_CPU_X86_FAMILY)
86
Peter Boström20a6e682024-09-30 22:10:1187CPU::CPU() {
88 Initialize();
[email protected]de8d26672008-09-25 22:08:4489}
Peter Boström20a6e682024-09-30 22:10:1190
Richard Townsend66bf8b72021-02-18 23:39:5791CPU::CPU(CPU&&) = default;
[email protected]de8d26672008-09-25 22:08:4492
[email protected]f3d445e2013-11-22 18:35:0393namespace {
94
[email protected]7e6d42b2011-02-16 18:51:5895#if defined(ARCH_CPU_X86_FAMILY)
Thiago Farinaba7d2a422017-06-17 00:18:4996#if !defined(COMPILER_MSVC)
[email protected]7e6d42b2011-02-16 18:51:5897
98#if defined(__pic__) && defined(__i386__)
99
James Zern8a904ed2024-05-08 23:28:27100// Requests extended feature information via |ecx|.
101void __cpuidex(int cpu_info[4], int eax, int ecx) {
Jan Keitel6c981202024-08-06 09:02:45102 // SAFETY: `cpu_info` has length 4 and therefore all accesses below are valid.
103 UNSAFE_BUFFERS(
104 __asm__ volatile("mov %%ebx, %%edi\n"
105 "cpuid\n"
106 "xchg %%edi, %%ebx\n"
107 : "=a"(cpu_info[0]), "=D"(cpu_info[1]),
108 "=c"(cpu_info[2]), "=d"(cpu_info[3])
109 : "a"(eax), "c"(ecx)));
James Zern8a904ed2024-05-08 23:28:27110}
111
112void __cpuid(int cpu_info[4], int info_type) {
113 __cpuidex(cpu_info, info_type, /*ecx=*/0);
[email protected]7e6d42b2011-02-16 18:51:58114}
115
[email protected]7e6d42b2011-02-16 18:51:58116#else
117
James Zern8a904ed2024-05-08 23:28:27118// Requests extended feature information via |ecx|.
119void __cpuidex(int cpu_info[4], int eax, int ecx) {
Jan Keitel6c981202024-08-06 09:02:45120 // SAFETY: `cpu_info` has length 4 and therefore all accesses below are valid.
121 UNSAFE_BUFFERS(__asm__ volatile("cpuid\n"
122 : "=a"(cpu_info[0]), "=b"(cpu_info[1]),
123 "=c"(cpu_info[2]), "=d"(cpu_info[3])
124 : "a"(eax), "c"(ecx)));
James Zern8a904ed2024-05-08 23:28:27125}
126
127void __cpuid(int cpu_info[4], int info_type) {
128 __cpuidex(cpu_info, info_type, /*ecx=*/0);
[email protected]7e6d42b2011-02-16 18:51:58129}
130
[email protected]f3d445e2013-11-22 18:35:03131#endif
Jordan Rupprechtc8970c82019-01-23 22:08:01132#endif // !defined(COMPILER_MSVC)
[email protected]f3d445e2013-11-22 18:35:03133
Jordan Rupprechtc8970c82019-01-23 22:08:01134// xgetbv returns the value of an Intel Extended Control Register (XCR).
[email protected]f3d445e2013-11-22 18:35:03135// Currently only XCR0 is defined by Intel so |xcr| should always be zero.
Jordan Rupprechtc8970c82019-01-23 22:08:01136uint64_t xgetbv(uint32_t xcr) {
137#if defined(COMPILER_MSVC)
138 return _xgetbv(xcr);
139#else
avi9b6f42932015-12-26 22:15:14140 uint32_t eax, edx;
[email protected]f3d445e2013-11-22 18:35:03141
Peter Kasting134ef9af2024-12-28 02:30:09142 __asm__ volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
avi9b6f42932015-12-26 22:15:14143 return (static_cast<uint64_t>(edx) << 32) | eax;
Jordan Rupprechtc8970c82019-01-23 22:08:01144#endif // defined(COMPILER_MSVC)
[email protected]7e6d42b2011-02-16 18:51:58145}
146
[email protected]7e6d42b2011-02-16 18:51:58147#endif // ARCH_CPU_X86_FAMILY
148
Jeffrey Gour6f946aad2024-07-11 16:07:54149DEFINE_PROTECTED_DATA base::ProtectedMemory<CPU> g_cpu_instance;
André Kempe1994caac2024-04-05 15:01:39150
Lei Zhang49c4b2a2017-11-03 21:34:23151} // namespace
[email protected]f3d445e2013-11-22 18:35:03152
Peter Boström20a6e682024-09-30 22:10:11153void CPU::Initialize() {
[email protected]7e6d42b2011-02-16 18:51:58154#if defined(ARCH_CPU_X86_FAMILY)
Arthur Sonzogni299864be12024-12-04 16:52:02155 int cpu_info[4] = {-1, 0, 0, 0};
[email protected]de8d26672008-09-25 22:08:44156
157 // __cpuid with an InfoType argument of 0 returns the number of
158 // valid Ids in CPUInfo[0] and the CPU identification string in
159 // the other three array elements. The CPU identification string is
[email protected]52a261f2009-03-03 15:01:12160 // not in linear order. The code below arranges the information
[email protected]595d1592012-10-04 21:05:23161 // in a human readable form. The human readable order is CPUInfo[1] |
162 // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped
Jan Keitel6c981202024-08-06 09:02:45163 // before copying these three array elements to |cpu_vendor_|.
[email protected]de8d26672008-09-25 22:08:44164 __cpuid(cpu_info, 0);
165 int num_ids = cpu_info[0];
[email protected]595d1592012-10-04 21:05:23166 std::swap(cpu_info[2], cpu_info[3]);
Jan Keitel6c981202024-08-06 09:02:45167 {
168 SpanWriter writer{span(cpu_vendor_)};
169 writer.Write(as_chars(span(cpu_info)).last<kVendorNameSize>());
170 writer.Write('\0');
171 }
[email protected]de8d26672008-09-25 22:08:44172
173 // Interpret CPU feature information.
[email protected]7f0813642008-09-26 23:26:34174 if (num_ids > 0) {
Arthur Sonzogni299864be12024-12-04 16:52:02175 int cpu_info7[4] = {};
176 int cpu_einfo7[4] = {};
[email protected]7f0813642008-09-26 23:26:34177 __cpuid(cpu_info, 1);
fbarchard0ce41ae2015-10-02 03:23:19178 if (num_ids >= 7) {
179 __cpuid(cpu_info7, 7);
James Zern8a904ed2024-05-08 23:28:27180 if (cpu_info7[0] >= 1) {
181 __cpuidex(cpu_einfo7, 7, 1);
182 }
fbarchard0ce41ae2015-10-02 03:23:19183 }
[email protected]5c8f89f692013-07-18 11:13:28184 signature_ = cpu_info[0];
[email protected]7f0813642008-09-26 23:26:34185 stepping_ = cpu_info[0] & 0xf;
[email protected]7f0813642008-09-26 23:26:34186 type_ = (cpu_info[0] >> 12) & 0x3;
Lei Zhang1b1116c52021-05-14 22:54:38187 internal::X86ModelInfo results =
Gabriel Marin8fdd7772019-08-17 00:28:09188 internal::ComputeX86FamilyAndModel(cpu_vendor_, signature_);
Lei Zhang1b1116c52021-05-14 22:54:38189 family_ = results.family;
190 model_ = results.model;
191 ext_family_ = results.ext_family;
192 ext_model_ = results.ext_model;
Peter Kasting134ef9af2024-12-28 02:30:09193 has_mmx_ = (cpu_info[3] & 0x00800000) != 0;
194 has_sse_ = (cpu_info[3] & 0x02000000) != 0;
195 has_sse2_ = (cpu_info[3] & 0x04000000) != 0;
196 has_sse3_ = (cpu_info[2] & 0x00000001) != 0;
[email protected]7e6d42b2011-02-16 18:51:58197 has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
198 has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
199 has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
ilevyb7d2f4082016-10-30 20:46:57200 has_popcnt_ = (cpu_info[2] & 0x00800000) != 0;
201
Rick James4aea59b92019-01-18 02:25:47202 // "Hypervisor Present Bit: Bit 31 of ECX of CPUID leaf 0x1."
203 // See https://lwn.net/Articles/301888/
204 // This is checking for any hypervisor. Hypervisors may choose not to
205 // announce themselves. Hypervisors trap CPUID and sometimes return
206 // different results to underlying hardware.
Peter Kastingde85e742022-06-01 17:41:54207 is_running_in_vm_ = (static_cast<uint32_t>(cpu_info[2]) & 0x80000000) != 0;
Rick James4aea59b92019-01-18 02:25:47208
[email protected]f3d445e2013-11-22 18:35:03209 // AVX instructions will generate an illegal instruction exception unless
210 // a) they are supported by the CPU,
211 // b) XSAVE is supported by the CPU and
212 // c) XSAVE is enabled by the kernel.
213 // See http://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled
[email protected]26ce2f62014-05-28 23:28:48214 //
215 // In addition, we have observed some crashes with the xgetbv instruction
216 // even after following Intel's example code. (See crbug.com/375968.)
217 // Because of that, we also test the XSAVE bit because its description in
218 // the CPUID documentation suggests that it signals xgetbv support.
Peter Kasting134ef9af2024-12-28 02:30:09219 has_avx_ = (cpu_info[2] & 0x10000000) != 0 &&
220 (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
221 (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
222 (xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */;
[email protected]b54d16d2013-12-02 16:15:03223 has_aesni_ = (cpu_info[2] & 0x02000000) != 0;
Ng Zhi An03baf5e2021-10-04 22:56:52224 has_fma3_ = (cpu_info[2] & 0x00001000) != 0;
James Zern8a904ed2024-05-08 23:28:27225 if (has_avx_) {
226 has_avx2_ = (cpu_info7[1] & 0x00000020) != 0;
227 has_avx_vnni_ = (cpu_einfo7[0] & 0x00000010) != 0;
228 // Check AVX-512 state, bits 5-7.
229 if ((xgetbv(0) & 0xe0) == 0xe0) {
230 has_avx512_f_ = (cpu_info7[1] & 0x00010000) != 0;
231 has_avx512_bw_ = (cpu_info7[1] & 0x40000000) != 0;
232 has_avx512_vnni_ = (cpu_info7[2] & 0x00000800) != 0;
233 }
234 }
Stephen Roettger6f1a4242022-10-07 10:04:25235
Simon Shields5407f842022-11-17 22:23:16236 has_pku_ = (cpu_info7[2] & 0x00000010) != 0;
Steinar H. Gundersonabf09a02025-05-12 14:00:33237 has_pclmul_ = (cpu_info[2] & 0x00000002) != 0;
[email protected]7f0813642008-09-26 23:26:34238 }
[email protected]595d1592012-10-04 21:05:23239
240 // Get the brand string of the cpu.
Peter Kastingde85e742022-06-01 17:41:54241 __cpuid(cpu_info, static_cast<int>(0x80000000));
242 const uint32_t max_parameter = static_cast<uint32_t>(cpu_info[0]);
[email protected]595d1592012-10-04 21:05:23243
Peter Kastingde85e742022-06-01 17:41:54244 static constexpr uint32_t kParameterStart = 0x80000002;
245 static constexpr uint32_t kParameterEnd = 0x80000004;
246 static constexpr uint32_t kParameterSize =
247 kParameterEnd - kParameterStart + 1;
André Kempe1994caac2024-04-05 15:01:39248 static_assert(kParameterSize * sizeof(cpu_info) == kBrandNameSize,
249 "cpu_brand_ has wrong size");
[email protected]595d1592012-10-04 21:05:23250
Lei Zhang49c4b2a2017-11-03 21:34:23251 if (max_parameter >= kParameterEnd) {
Jan Keitel6c981202024-08-06 09:02:45252 SpanWriter writer{span(cpu_brand_)};
Peter Kastingde85e742022-06-01 17:41:54253 for (uint32_t parameter = kParameterStart; parameter <= kParameterEnd;
Lei Zhang49c4b2a2017-11-03 21:34:23254 ++parameter) {
Peter Kastingde85e742022-06-01 17:41:54255 __cpuid(cpu_info, static_cast<int>(parameter));
Jan Keitel6c981202024-08-06 09:02:45256 writer.Write(as_chars(span(cpu_info)));
[email protected]595d1592012-10-04 21:05:23257 }
Jan Keitel6c981202024-08-06 09:02:45258 writer.Write('\0');
[email protected]595d1592012-10-04 21:05:23259 }
[email protected]aa312812013-04-30 19:46:05260
Peter Kastingde85e742022-06-01 17:41:54261 static constexpr uint32_t kParameterContainingNonStopTimeStampCounter =
262 0x80000007;
Lei Zhang49c4b2a2017-11-03 21:34:23263 if (max_parameter >= kParameterContainingNonStopTimeStampCounter) {
Peter Kastingde85e742022-06-01 17:41:54264 __cpuid(cpu_info,
265 static_cast<int>(kParameterContainingNonStopTimeStampCounter));
[email protected]aa312812013-04-30 19:46:05266 has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0;
267 }
Rick James4aea59b92019-01-18 02:25:47268
Julian Pastarmov6f4a3182019-06-26 07:00:43269 if (!has_non_stop_time_stamp_counter_ && is_running_in_vm_) {
Rick James4aea59b92019-01-18 02:25:47270 int cpu_info_hv[4] = {};
271 __cpuid(cpu_info_hv, 0x40000000);
272 if (cpu_info_hv[1] == 0x7263694D && // Micr
273 cpu_info_hv[2] == 0x666F736F && // osof
274 cpu_info_hv[3] == 0x76482074) { // t Hv
275 // If CPUID says we have a variant TSC and a hypervisor has identified
276 // itself and the hypervisor says it is Microsoft Hyper-V, then treat
277 // TSC as invariant.
278 //
279 // Microsoft Hyper-V hypervisor reports variant TSC as there are some
280 // scenarios (eg. VM live migration) where the TSC is variant, but for
281 // our purposes we can treat it as invariant.
282 has_non_stop_time_stamp_counter_ = true;
283 }
284 }
Richard Townsend17f9606a2019-05-07 15:57:06285#elif defined(ARCH_CPU_ARM_FAMILY)
Peter Boström20a6e682024-09-30 22:10:11286#if defined(ARCH_CPU_ARM64) && \
287 (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
Richard Townsend8cb7ba0b2020-11-26 23:23:22288 // Check for Armv8.5-A BTI/MTE support, exposed via HWCAP2
289 unsigned long hwcap2 = getauxval(AT_HWCAP2);
290 has_mte_ = hwcap2 & HWCAP2_MTE;
291 has_bti_ = hwcap2 & HWCAP2_BTI;
Xiaohan Wang38e4ebb2022-01-19 06:57:43292#elif BUILDFLAG(IS_WIN)
Richard Townsend17f9606a2019-05-07 15:57:06293 // Windows makes high-resolution thread timing information available in
294 // user-space.
295 has_non_stop_time_stamp_counter_ = true;
296#endif
[email protected]7e6d42b2011-02-16 18:51:58297#endif
[email protected]de8d26672008-09-25 22:08:44298}
299
Lei Zhange668a1d2022-01-04 21:06:33300#if defined(ARCH_CPU_X86_FAMILY)
[email protected]5016a9dd2013-02-02 01:10:02301CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
Peter Kasting134ef9af2024-12-28 02:30:09302 if (has_avx512_vnni()) {
303 return AVX512_VNNI;
304 }
305 if (has_avx512_bw()) {
306 return AVX512BW;
307 }
308 if (has_avx512_f()) {
309 return AVX512F;
310 }
311 if (has_avx_vnni()) {
312 return AVX_VNNI;
313 }
314 if (has_avx2()) {
315 return AVX2;
316 }
317 if (has_fma3()) {
318 return FMA3;
319 }
320 if (has_avx()) {
321 return AVX;
322 }
323 if (has_sse42()) {
324 return SSE42;
325 }
326 if (has_sse41()) {
327 return SSE41;
328 }
329 if (has_ssse3()) {
330 return SSSE3;
331 }
332 if (has_sse3()) {
333 return SSE3;
334 }
335 if (has_sse2()) {
336 return SSE2;
337 }
338 if (has_sse()) {
339 return SSE;
340 }
[email protected]5016a9dd2013-02-02 01:10:02341 return PENTIUM;
342}
Lei Zhange668a1d2022-01-04 21:06:33343#endif
[email protected]5016a9dd2013-02-02 01:10:02344
André Kempe60269112021-09-17 13:14:11345const CPU& CPU::GetInstanceNoAllocation() {
Peter Boström20a6e682024-09-30 22:10:11346 static ProtectedMemoryInitializer cpu_initializer(g_cpu_instance, CPU());
André Kempe60269112021-09-17 13:14:11347
André Kempe1994caac2024-04-05 15:01:39348 return *g_cpu_instance;
André Kempe60269112021-09-17 13:14:11349}
350
[email protected]de8d26672008-09-25 22:08:44351} // namespace base