1*9356374aSAndroid Build Coastguard Worker // Copyright 2022 The Abseil Authors
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker
15*9356374aSAndroid Build Coastguard Worker #include "absl/crc/internal/cpu_detect.h"
16*9356374aSAndroid Build Coastguard Worker
17*9356374aSAndroid Build Coastguard Worker #include <cstdint>
18*9356374aSAndroid Build Coastguard Worker #include <string>
19*9356374aSAndroid Build Coastguard Worker
20*9356374aSAndroid Build Coastguard Worker #include "absl/base/config.h"
21*9356374aSAndroid Build Coastguard Worker
22*9356374aSAndroid Build Coastguard Worker #if defined(__aarch64__) && defined(__linux__)
23*9356374aSAndroid Build Coastguard Worker #include <asm/hwcap.h>
24*9356374aSAndroid Build Coastguard Worker #include <sys/auxv.h>
25*9356374aSAndroid Build Coastguard Worker #endif
26*9356374aSAndroid Build Coastguard Worker
27*9356374aSAndroid Build Coastguard Worker #if defined(_WIN32) || defined(_WIN64)
28*9356374aSAndroid Build Coastguard Worker #include <intrin.h>
29*9356374aSAndroid Build Coastguard Worker #endif
30*9356374aSAndroid Build Coastguard Worker
31*9356374aSAndroid Build Coastguard Worker #if defined(__x86_64__) || defined(_M_X64)
32*9356374aSAndroid Build Coastguard Worker #if ABSL_HAVE_BUILTIN(__cpuid)
33*9356374aSAndroid Build Coastguard Worker // MSVC-equivalent __cpuid intrinsic declaration for clang-like compilers
34*9356374aSAndroid Build Coastguard Worker // for non-Windows build environments.
35*9356374aSAndroid Build Coastguard Worker extern void __cpuid(int[4], int);
36*9356374aSAndroid Build Coastguard Worker #elif !defined(_WIN32) && !defined(_WIN64)
37*9356374aSAndroid Build Coastguard Worker // MSVC defines this function for us.
38*9356374aSAndroid Build Coastguard Worker // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex
__cpuid(int cpu_info[4],int info_type)39*9356374aSAndroid Build Coastguard Worker static void __cpuid(int cpu_info[4], int info_type) {
40*9356374aSAndroid Build Coastguard Worker __asm__ volatile("cpuid \n\t"
41*9356374aSAndroid Build Coastguard Worker : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]),
42*9356374aSAndroid Build Coastguard Worker "=d"(cpu_info[3])
43*9356374aSAndroid Build Coastguard Worker : "a"(info_type), "c"(0));
44*9356374aSAndroid Build Coastguard Worker }
45*9356374aSAndroid Build Coastguard Worker #endif // !defined(_WIN32) && !defined(_WIN64)
46*9356374aSAndroid Build Coastguard Worker #endif // defined(__x86_64__) || defined(_M_X64)
47*9356374aSAndroid Build Coastguard Worker
48*9356374aSAndroid Build Coastguard Worker namespace absl {
49*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
50*9356374aSAndroid Build Coastguard Worker namespace crc_internal {
51*9356374aSAndroid Build Coastguard Worker
52*9356374aSAndroid Build Coastguard Worker #if defined(__x86_64__) || defined(_M_X64)
53*9356374aSAndroid Build Coastguard Worker
54*9356374aSAndroid Build Coastguard Worker namespace {
55*9356374aSAndroid Build Coastguard Worker
56*9356374aSAndroid Build Coastguard Worker enum class Vendor {
57*9356374aSAndroid Build Coastguard Worker kUnknown,
58*9356374aSAndroid Build Coastguard Worker kIntel,
59*9356374aSAndroid Build Coastguard Worker kAmd,
60*9356374aSAndroid Build Coastguard Worker };
61*9356374aSAndroid Build Coastguard Worker
GetVendor()62*9356374aSAndroid Build Coastguard Worker Vendor GetVendor() {
63*9356374aSAndroid Build Coastguard Worker // Get the vendor string (issue CPUID with eax = 0).
64*9356374aSAndroid Build Coastguard Worker int cpu_info[4];
65*9356374aSAndroid Build Coastguard Worker __cpuid(cpu_info, 0);
66*9356374aSAndroid Build Coastguard Worker
67*9356374aSAndroid Build Coastguard Worker std::string vendor;
68*9356374aSAndroid Build Coastguard Worker vendor.append(reinterpret_cast<char*>(&cpu_info[1]), 4);
69*9356374aSAndroid Build Coastguard Worker vendor.append(reinterpret_cast<char*>(&cpu_info[3]), 4);
70*9356374aSAndroid Build Coastguard Worker vendor.append(reinterpret_cast<char*>(&cpu_info[2]), 4);
71*9356374aSAndroid Build Coastguard Worker if (vendor == "GenuineIntel") {
72*9356374aSAndroid Build Coastguard Worker return Vendor::kIntel;
73*9356374aSAndroid Build Coastguard Worker } else if (vendor == "AuthenticAMD") {
74*9356374aSAndroid Build Coastguard Worker return Vendor::kAmd;
75*9356374aSAndroid Build Coastguard Worker } else {
76*9356374aSAndroid Build Coastguard Worker return Vendor::kUnknown;
77*9356374aSAndroid Build Coastguard Worker }
78*9356374aSAndroid Build Coastguard Worker }
79*9356374aSAndroid Build Coastguard Worker
GetIntelCpuType()80*9356374aSAndroid Build Coastguard Worker CpuType GetIntelCpuType() {
81*9356374aSAndroid Build Coastguard Worker // To get general information and extended features we send eax = 1 and
82*9356374aSAndroid Build Coastguard Worker // ecx = 0 to cpuid. The response is returned in eax, ebx, ecx and edx.
83*9356374aSAndroid Build Coastguard Worker // (See Intel 64 and IA-32 Architectures Software Developer's Manual
84*9356374aSAndroid Build Coastguard Worker // Volume 2A: Instruction Set Reference, A-M CPUID).
85*9356374aSAndroid Build Coastguard Worker // https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html
86*9356374aSAndroid Build Coastguard Worker // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex
87*9356374aSAndroid Build Coastguard Worker int cpu_info[4];
88*9356374aSAndroid Build Coastguard Worker __cpuid(cpu_info, 1);
89*9356374aSAndroid Build Coastguard Worker
90*9356374aSAndroid Build Coastguard Worker // Response in eax bits as follows:
91*9356374aSAndroid Build Coastguard Worker // 0-3 (stepping id)
92*9356374aSAndroid Build Coastguard Worker // 4-7 (model number),
93*9356374aSAndroid Build Coastguard Worker // 8-11 (family code),
94*9356374aSAndroid Build Coastguard Worker // 12-13 (processor type),
95*9356374aSAndroid Build Coastguard Worker // 16-19 (extended model)
96*9356374aSAndroid Build Coastguard Worker // 20-27 (extended family)
97*9356374aSAndroid Build Coastguard Worker
98*9356374aSAndroid Build Coastguard Worker int family = (cpu_info[0] >> 8) & 0x0f;
99*9356374aSAndroid Build Coastguard Worker int model_num = (cpu_info[0] >> 4) & 0x0f;
100*9356374aSAndroid Build Coastguard Worker int ext_family = (cpu_info[0] >> 20) & 0xff;
101*9356374aSAndroid Build Coastguard Worker int ext_model_num = (cpu_info[0] >> 16) & 0x0f;
102*9356374aSAndroid Build Coastguard Worker
103*9356374aSAndroid Build Coastguard Worker int brand_id = cpu_info[1] & 0xff;
104*9356374aSAndroid Build Coastguard Worker
105*9356374aSAndroid Build Coastguard Worker // Process the extended family and model info if necessary
106*9356374aSAndroid Build Coastguard Worker if (family == 0x0f) {
107*9356374aSAndroid Build Coastguard Worker family += ext_family;
108*9356374aSAndroid Build Coastguard Worker }
109*9356374aSAndroid Build Coastguard Worker
110*9356374aSAndroid Build Coastguard Worker if (family == 0x0f || family == 0x6) {
111*9356374aSAndroid Build Coastguard Worker model_num += (ext_model_num << 4);
112*9356374aSAndroid Build Coastguard Worker }
113*9356374aSAndroid Build Coastguard Worker
114*9356374aSAndroid Build Coastguard Worker switch (brand_id) {
115*9356374aSAndroid Build Coastguard Worker case 0: // no brand ID, so parse CPU family/model
116*9356374aSAndroid Build Coastguard Worker switch (family) {
117*9356374aSAndroid Build Coastguard Worker case 6: // Most PentiumIII processors are in this category
118*9356374aSAndroid Build Coastguard Worker switch (model_num) {
119*9356374aSAndroid Build Coastguard Worker case 0x2c: // Westmere: Gulftown
120*9356374aSAndroid Build Coastguard Worker return CpuType::kIntelWestmere;
121*9356374aSAndroid Build Coastguard Worker case 0x2d: // Sandybridge
122*9356374aSAndroid Build Coastguard Worker return CpuType::kIntelSandybridge;
123*9356374aSAndroid Build Coastguard Worker case 0x3e: // Ivybridge
124*9356374aSAndroid Build Coastguard Worker return CpuType::kIntelIvybridge;
125*9356374aSAndroid Build Coastguard Worker case 0x3c: // Haswell (client)
126*9356374aSAndroid Build Coastguard Worker case 0x3f: // Haswell
127*9356374aSAndroid Build Coastguard Worker return CpuType::kIntelHaswell;
128*9356374aSAndroid Build Coastguard Worker case 0x4f: // Broadwell
129*9356374aSAndroid Build Coastguard Worker case 0x56: // BroadwellDE
130*9356374aSAndroid Build Coastguard Worker return CpuType::kIntelBroadwell;
131*9356374aSAndroid Build Coastguard Worker case 0x55: // Skylake Xeon
132*9356374aSAndroid Build Coastguard Worker if ((cpu_info[0] & 0x0f) < 5) { // stepping < 5 is skylake
133*9356374aSAndroid Build Coastguard Worker return CpuType::kIntelSkylakeXeon;
134*9356374aSAndroid Build Coastguard Worker } else { // stepping >= 5 is cascadelake
135*9356374aSAndroid Build Coastguard Worker return CpuType::kIntelCascadelakeXeon;
136*9356374aSAndroid Build Coastguard Worker }
137*9356374aSAndroid Build Coastguard Worker case 0x5e: // Skylake (client)
138*9356374aSAndroid Build Coastguard Worker return CpuType::kIntelSkylake;
139*9356374aSAndroid Build Coastguard Worker default:
140*9356374aSAndroid Build Coastguard Worker return CpuType::kUnknown;
141*9356374aSAndroid Build Coastguard Worker }
142*9356374aSAndroid Build Coastguard Worker default:
143*9356374aSAndroid Build Coastguard Worker return CpuType::kUnknown;
144*9356374aSAndroid Build Coastguard Worker }
145*9356374aSAndroid Build Coastguard Worker default:
146*9356374aSAndroid Build Coastguard Worker return CpuType::kUnknown;
147*9356374aSAndroid Build Coastguard Worker }
148*9356374aSAndroid Build Coastguard Worker }
149*9356374aSAndroid Build Coastguard Worker
GetAmdCpuType()150*9356374aSAndroid Build Coastguard Worker CpuType GetAmdCpuType() {
151*9356374aSAndroid Build Coastguard Worker // To get general information and extended features we send eax = 1 and
152*9356374aSAndroid Build Coastguard Worker // ecx = 0 to cpuid. The response is returned in eax, ebx, ecx and edx.
153*9356374aSAndroid Build Coastguard Worker // (See Intel 64 and IA-32 Architectures Software Developer's Manual
154*9356374aSAndroid Build Coastguard Worker // Volume 2A: Instruction Set Reference, A-M CPUID).
155*9356374aSAndroid Build Coastguard Worker // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex
156*9356374aSAndroid Build Coastguard Worker int cpu_info[4];
157*9356374aSAndroid Build Coastguard Worker __cpuid(cpu_info, 1);
158*9356374aSAndroid Build Coastguard Worker
159*9356374aSAndroid Build Coastguard Worker // Response in eax bits as follows:
160*9356374aSAndroid Build Coastguard Worker // 0-3 (stepping id)
161*9356374aSAndroid Build Coastguard Worker // 4-7 (model number),
162*9356374aSAndroid Build Coastguard Worker // 8-11 (family code),
163*9356374aSAndroid Build Coastguard Worker // 12-13 (processor type),
164*9356374aSAndroid Build Coastguard Worker // 16-19 (extended model)
165*9356374aSAndroid Build Coastguard Worker // 20-27 (extended family)
166*9356374aSAndroid Build Coastguard Worker
167*9356374aSAndroid Build Coastguard Worker int family = (cpu_info[0] >> 8) & 0x0f;
168*9356374aSAndroid Build Coastguard Worker int model_num = (cpu_info[0] >> 4) & 0x0f;
169*9356374aSAndroid Build Coastguard Worker int ext_family = (cpu_info[0] >> 20) & 0xff;
170*9356374aSAndroid Build Coastguard Worker int ext_model_num = (cpu_info[0] >> 16) & 0x0f;
171*9356374aSAndroid Build Coastguard Worker
172*9356374aSAndroid Build Coastguard Worker if (family == 0x0f) {
173*9356374aSAndroid Build Coastguard Worker family += ext_family;
174*9356374aSAndroid Build Coastguard Worker model_num += (ext_model_num << 4);
175*9356374aSAndroid Build Coastguard Worker }
176*9356374aSAndroid Build Coastguard Worker
177*9356374aSAndroid Build Coastguard Worker switch (family) {
178*9356374aSAndroid Build Coastguard Worker case 0x17:
179*9356374aSAndroid Build Coastguard Worker switch (model_num) {
180*9356374aSAndroid Build Coastguard Worker case 0x0: // Stepping Ax
181*9356374aSAndroid Build Coastguard Worker case 0x1: // Stepping Bx
182*9356374aSAndroid Build Coastguard Worker return CpuType::kAmdNaples;
183*9356374aSAndroid Build Coastguard Worker case 0x30: // Stepping Ax
184*9356374aSAndroid Build Coastguard Worker case 0x31: // Stepping Bx
185*9356374aSAndroid Build Coastguard Worker return CpuType::kAmdRome;
186*9356374aSAndroid Build Coastguard Worker default:
187*9356374aSAndroid Build Coastguard Worker return CpuType::kUnknown;
188*9356374aSAndroid Build Coastguard Worker }
189*9356374aSAndroid Build Coastguard Worker break;
190*9356374aSAndroid Build Coastguard Worker case 0x19:
191*9356374aSAndroid Build Coastguard Worker switch (model_num) {
192*9356374aSAndroid Build Coastguard Worker case 0x0: // Stepping Ax
193*9356374aSAndroid Build Coastguard Worker case 0x1: // Stepping B0
194*9356374aSAndroid Build Coastguard Worker return CpuType::kAmdMilan;
195*9356374aSAndroid Build Coastguard Worker case 0x10: // Stepping A0
196*9356374aSAndroid Build Coastguard Worker case 0x11: // Stepping B0
197*9356374aSAndroid Build Coastguard Worker return CpuType::kAmdGenoa;
198*9356374aSAndroid Build Coastguard Worker case 0x44: // Stepping A0
199*9356374aSAndroid Build Coastguard Worker return CpuType::kAmdRyzenV3000;
200*9356374aSAndroid Build Coastguard Worker default:
201*9356374aSAndroid Build Coastguard Worker return CpuType::kUnknown;
202*9356374aSAndroid Build Coastguard Worker }
203*9356374aSAndroid Build Coastguard Worker break;
204*9356374aSAndroid Build Coastguard Worker default:
205*9356374aSAndroid Build Coastguard Worker return CpuType::kUnknown;
206*9356374aSAndroid Build Coastguard Worker }
207*9356374aSAndroid Build Coastguard Worker }
208*9356374aSAndroid Build Coastguard Worker
209*9356374aSAndroid Build Coastguard Worker } // namespace
210*9356374aSAndroid Build Coastguard Worker
GetCpuType()211*9356374aSAndroid Build Coastguard Worker CpuType GetCpuType() {
212*9356374aSAndroid Build Coastguard Worker switch (GetVendor()) {
213*9356374aSAndroid Build Coastguard Worker case Vendor::kIntel:
214*9356374aSAndroid Build Coastguard Worker return GetIntelCpuType();
215*9356374aSAndroid Build Coastguard Worker case Vendor::kAmd:
216*9356374aSAndroid Build Coastguard Worker return GetAmdCpuType();
217*9356374aSAndroid Build Coastguard Worker default:
218*9356374aSAndroid Build Coastguard Worker return CpuType::kUnknown;
219*9356374aSAndroid Build Coastguard Worker }
220*9356374aSAndroid Build Coastguard Worker }
221*9356374aSAndroid Build Coastguard Worker
SupportsArmCRC32PMULL()222*9356374aSAndroid Build Coastguard Worker bool SupportsArmCRC32PMULL() { return false; }
223*9356374aSAndroid Build Coastguard Worker
224*9356374aSAndroid Build Coastguard Worker #elif defined(__aarch64__) && defined(__linux__)
225*9356374aSAndroid Build Coastguard Worker
226*9356374aSAndroid Build Coastguard Worker #ifndef HWCAP_CPUID
227*9356374aSAndroid Build Coastguard Worker #define HWCAP_CPUID (1 << 11)
228*9356374aSAndroid Build Coastguard Worker #endif
229*9356374aSAndroid Build Coastguard Worker
230*9356374aSAndroid Build Coastguard Worker #define ABSL_INTERNAL_AARCH64_ID_REG_READ(id, val) \
231*9356374aSAndroid Build Coastguard Worker asm("mrs %0, " #id : "=r"(val))
232*9356374aSAndroid Build Coastguard Worker
233*9356374aSAndroid Build Coastguard Worker CpuType GetCpuType() {
234*9356374aSAndroid Build Coastguard Worker // MIDR_EL1 is not visible to EL0, however the access will be emulated by
235*9356374aSAndroid Build Coastguard Worker // linux if AT_HWCAP has HWCAP_CPUID set.
236*9356374aSAndroid Build Coastguard Worker //
237*9356374aSAndroid Build Coastguard Worker // This method will be unreliable on heterogeneous computing systems (ex:
238*9356374aSAndroid Build Coastguard Worker // big.LITTLE) since the value of MIDR_EL1 will change based on the calling
239*9356374aSAndroid Build Coastguard Worker // thread.
240*9356374aSAndroid Build Coastguard Worker uint64_t hwcaps = getauxval(AT_HWCAP);
241*9356374aSAndroid Build Coastguard Worker if (hwcaps & HWCAP_CPUID) {
242*9356374aSAndroid Build Coastguard Worker uint64_t midr = 0;
243*9356374aSAndroid Build Coastguard Worker ABSL_INTERNAL_AARCH64_ID_REG_READ(MIDR_EL1, midr);
244*9356374aSAndroid Build Coastguard Worker uint32_t implementer = (midr >> 24) & 0xff;
245*9356374aSAndroid Build Coastguard Worker uint32_t part_number = (midr >> 4) & 0xfff;
246*9356374aSAndroid Build Coastguard Worker switch (implementer) {
247*9356374aSAndroid Build Coastguard Worker case 0x41:
248*9356374aSAndroid Build Coastguard Worker switch (part_number) {
249*9356374aSAndroid Build Coastguard Worker case 0xd0c: return CpuType::kArmNeoverseN1;
250*9356374aSAndroid Build Coastguard Worker case 0xd40: return CpuType::kArmNeoverseV1;
251*9356374aSAndroid Build Coastguard Worker case 0xd49: return CpuType::kArmNeoverseN2;
252*9356374aSAndroid Build Coastguard Worker case 0xd4f: return CpuType::kArmNeoverseV2;
253*9356374aSAndroid Build Coastguard Worker default:
254*9356374aSAndroid Build Coastguard Worker return CpuType::kUnknown;
255*9356374aSAndroid Build Coastguard Worker }
256*9356374aSAndroid Build Coastguard Worker break;
257*9356374aSAndroid Build Coastguard Worker case 0xc0:
258*9356374aSAndroid Build Coastguard Worker switch (part_number) {
259*9356374aSAndroid Build Coastguard Worker case 0xac3: return CpuType::kAmpereSiryn;
260*9356374aSAndroid Build Coastguard Worker default:
261*9356374aSAndroid Build Coastguard Worker return CpuType::kUnknown;
262*9356374aSAndroid Build Coastguard Worker }
263*9356374aSAndroid Build Coastguard Worker break;
264*9356374aSAndroid Build Coastguard Worker default:
265*9356374aSAndroid Build Coastguard Worker return CpuType::kUnknown;
266*9356374aSAndroid Build Coastguard Worker }
267*9356374aSAndroid Build Coastguard Worker }
268*9356374aSAndroid Build Coastguard Worker return CpuType::kUnknown;
269*9356374aSAndroid Build Coastguard Worker }
270*9356374aSAndroid Build Coastguard Worker
271*9356374aSAndroid Build Coastguard Worker bool SupportsArmCRC32PMULL() {
272*9356374aSAndroid Build Coastguard Worker uint64_t hwcaps = getauxval(AT_HWCAP);
273*9356374aSAndroid Build Coastguard Worker return (hwcaps & HWCAP_CRC32) && (hwcaps & HWCAP_PMULL);
274*9356374aSAndroid Build Coastguard Worker }
275*9356374aSAndroid Build Coastguard Worker
276*9356374aSAndroid Build Coastguard Worker #else
277*9356374aSAndroid Build Coastguard Worker
278*9356374aSAndroid Build Coastguard Worker CpuType GetCpuType() { return CpuType::kUnknown; }
279*9356374aSAndroid Build Coastguard Worker
280*9356374aSAndroid Build Coastguard Worker bool SupportsArmCRC32PMULL() { return false; }
281*9356374aSAndroid Build Coastguard Worker
282*9356374aSAndroid Build Coastguard Worker #endif
283*9356374aSAndroid Build Coastguard Worker
284*9356374aSAndroid Build Coastguard Worker } // namespace crc_internal
285*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
286*9356374aSAndroid Build Coastguard Worker } // namespace absl
287