390e8c92c9c8412fc09e98eb525e4803a77242f3
[iec.git] / src / type3_AndroidCloud / anbox-master / external / cpu_features / src / cpuinfo_x86.c
1 // Copyright 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "cpuinfo_x86.h"
16 #include "internal/bit_utils.h"
17 #include "internal/cpuid_x86.h"
18
19 #include <stdbool.h>
20 #include <string.h>
21
22 static const Leaf kEmptyLeaf;
23
24 static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id) {
25   if (leaf_id <= max_cpuid_leaf) {
26     return CpuId(leaf_id);
27   } else {
28     return kEmptyLeaf;
29   }
30 }
31
32 #define MASK_XMM 0x2
33 #define MASK_YMM 0x4
34 #define MASK_MASKREG 0x20
35 #define MASK_ZMM0_15 0x40
36 #define MASK_ZMM16_31 0x80
37
38 static bool HasMask(uint32_t value, uint32_t mask) {
39   return (value & mask) == mask;
40 }
41
42 // Checks that operating system saves and restores xmm registers during context
43 // switches.
44 static bool HasXmmOsXSave(uint32_t xcr0_eax) {
45   return HasMask(xcr0_eax, MASK_XMM);
46 }
47
48 // Checks that operating system saves and restores ymm registers during context
49 // switches.
50 static bool HasYmmOsXSave(uint32_t xcr0_eax) {
51   return HasMask(xcr0_eax, MASK_XMM | MASK_YMM);
52 }
53
54 // Checks that operating system saves and restores zmm registers during context
55 // switches.
56 static bool HasZmmOsXSave(uint32_t xcr0_eax) {
57   return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 |
58                                MASK_ZMM16_31);
59 }
60
61 static void SetVendor(const Leaf leaf, char* const vendor) {
62   *(uint32_t*)(vendor) = leaf.ebx;
63   *(uint32_t*)(vendor + 4) = leaf.edx;
64   *(uint32_t*)(vendor + 8) = leaf.ecx;
65   vendor[12] = '\0';
66 }
67
68 static int IsVendor(const Leaf leaf, const char* const name) {
69   const uint32_t ebx = *(const uint32_t*)(name);
70   const uint32_t edx = *(const uint32_t*)(name + 4);
71   const uint32_t ecx = *(const uint32_t*)(name + 8);
72   return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
73 }
74
75 // Reference https://en.wikipedia.org/wiki/CPUID.
76 static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info) {
77   const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
78   const Leaf leaf_7 = SafeCpuId(max_cpuid_leaf, 7);
79
80   const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
81   const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
82   const uint32_t xcr0_eax = (have_xsave && have_osxsave) ? GetXCR0Eax() : 0;
83   const bool have_sse_os_support = HasXmmOsXSave(xcr0_eax);
84   const bool have_avx_os_support = HasYmmOsXSave(xcr0_eax);
85   const bool have_avx512_os_support = HasZmmOsXSave(xcr0_eax);
86
87   const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8);
88   const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20);
89   const uint32_t model = ExtractBitRange(leaf_1.eax, 7, 4);
90   const uint32_t extended_model = ExtractBitRange(leaf_1.eax, 19, 16);
91
92   X86Features* const features = &info->features;
93
94   info->family = extended_family + family;
95   info->model = (extended_model << 4) + model;
96   info->stepping = ExtractBitRange(leaf_1.eax, 3, 0);
97
98   features->smx = IsBitSet(leaf_1.ecx, 6);
99   features->cx16 = IsBitSet(leaf_1.ecx, 13);
100   features->aes = IsBitSet(leaf_1.ecx, 25);
101   features->f16c = IsBitSet(leaf_1.ecx, 29);
102   features->sgx = IsBitSet(leaf_7.ebx, 2);
103   features->bmi1 = IsBitSet(leaf_7.ebx, 3);
104   features->bmi2 = IsBitSet(leaf_7.ebx, 8);
105   features->erms = IsBitSet(leaf_7.ebx, 9);
106   features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10);
107
108   if (have_sse_os_support) {
109     features->ssse3 = IsBitSet(leaf_1.ecx, 9);
110     features->sse4_1 = IsBitSet(leaf_1.ecx, 19);
111     features->sse4_2 = IsBitSet(leaf_1.ecx, 20);
112   }
113
114   if (have_avx_os_support) {
115     features->fma3 = IsBitSet(leaf_1.ecx, 12);
116     features->avx = IsBitSet(leaf_1.ecx, 28);
117     features->avx2 = IsBitSet(leaf_7.ebx, 5);
118   }
119
120   if (have_avx512_os_support) {
121     features->avx512f = IsBitSet(leaf_7.ebx, 16);
122     features->avx512cd = IsBitSet(leaf_7.ebx, 28);
123     features->avx512er = IsBitSet(leaf_7.ebx, 27);
124     features->avx512pf = IsBitSet(leaf_7.ebx, 26);
125     features->avx512bw = IsBitSet(leaf_7.ebx, 30);
126     features->avx512dq = IsBitSet(leaf_7.ebx, 17);
127     features->avx512vl = IsBitSet(leaf_7.ebx, 31);
128     features->avx512ifma = IsBitSet(leaf_7.ebx, 21);
129     features->avx512vbmi = IsBitSet(leaf_7.ecx, 1);
130     features->avx512vbmi2 = IsBitSet(leaf_7.ecx, 6);
131     features->avx512vnni = IsBitSet(leaf_7.ecx, 11);
132     features->avx512bitalg = IsBitSet(leaf_7.ecx, 12);
133     features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14);
134     features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2);
135     features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3);
136   }
137 }
138
139 static const X86Info kEmptyX86Info;
140
141 X86Info GetX86Info(void) {
142   X86Info info = kEmptyX86Info;
143   const Leaf leaf_0 = CpuId(0);
144   const uint32_t max_cpuid_leaf = leaf_0.eax;
145   SetVendor(leaf_0, info.vendor);
146   if (IsVendor(leaf_0, "GenuineIntel") || IsVendor(leaf_0, "AuthenticAMD")) {
147     ParseCpuId(max_cpuid_leaf, &info);
148   }
149   return info;
150 }
151
152 #define CPUID(FAMILY, MODEL) (((FAMILY & 0xFF) << 8) | (MODEL & 0xFF))
153
154 X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
155   if (memcmp(info->vendor, "GenuineIntel", sizeof(info->vendor)) == 0) {
156     switch (CPUID(info->family, info->model)) {
157       case CPUID(0x06, 0x35):
158       case CPUID(0x06, 0x36):
159         // https://en.wikipedia.org/wiki/Bonnell_(microarchitecture)
160         return INTEL_ATOM_BNL;
161       case CPUID(0x06, 0x37):
162       case CPUID(0x06, 0x4C):
163         // https://en.wikipedia.org/wiki/Silvermont
164         return INTEL_ATOM_SMT;
165       case CPUID(0x06, 0x5C):
166         // https://en.wikipedia.org/wiki/Goldmont
167         return INTEL_ATOM_GMT;
168       case CPUID(0x06, 0x0F):
169       case CPUID(0x06, 0x16):
170         // https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture)
171         return INTEL_CORE;
172       case CPUID(0x06, 0x17):
173       case CPUID(0x06, 0x1D):
174         // https://en.wikipedia.org/wiki/Penryn_(microarchitecture)
175         return INTEL_PNR;
176       case CPUID(0x06, 0x1A):
177       case CPUID(0x06, 0x1E):
178       case CPUID(0x06, 0x1F):
179       case CPUID(0x06, 0x2E):
180         // https://en.wikipedia.org/wiki/Nehalem_(microarchitecture)
181         return INTEL_NHM;
182       case CPUID(0x06, 0x25):
183       case CPUID(0x06, 0x2C):
184       case CPUID(0x06, 0x2F):
185         // https://en.wikipedia.org/wiki/Westmere_(microarchitecture)
186         return INTEL_WSM;
187       case CPUID(0x06, 0x2A):
188       case CPUID(0x06, 0x2D):
189         // https://en.wikipedia.org/wiki/Sandy_Bridge#Models_and_steppings
190         return INTEL_SNB;
191       case CPUID(0x06, 0x3A):
192       case CPUID(0x06, 0x3E):
193         // https://en.wikipedia.org/wiki/Ivy_Bridge_(microarchitecture)#Models_and_steppings
194         return INTEL_IVB;
195       case CPUID(0x06, 0x3C):
196       case CPUID(0x06, 0x3F):
197       case CPUID(0x06, 0x45):
198       case CPUID(0x06, 0x46):
199         // https://en.wikipedia.org/wiki/Haswell_(microarchitecture)
200         return INTEL_HSW;
201       case CPUID(0x06, 0x3D):
202       case CPUID(0x06, 0x47):
203       case CPUID(0x06, 0x4F):
204       case CPUID(0x06, 0x56):
205         // https://en.wikipedia.org/wiki/Broadwell_(microarchitecture)
206         return INTEL_BDW;
207       case CPUID(0x06, 0x4E):
208       case CPUID(0x06, 0x55):
209       case CPUID(0x06, 0x5E):
210         // https://en.wikipedia.org/wiki/Skylake_(microarchitecture)
211         return INTEL_SKL;
212       case CPUID(0x06, 0x8E):
213       case CPUID(0x06, 0x9E):
214         // https://en.wikipedia.org/wiki/Kaby_Lake
215         return INTEL_KBL;
216       default:
217         return X86_UNKNOWN;
218     }
219   }
220   if (memcmp(info->vendor, "AuthenticAMD", sizeof(info->vendor)) == 0) {
221     switch (info->family) {
222         // https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures
223       case 0x0F:
224         return AMD_HAMMER;
225       case 0x10:
226         return AMD_K10;
227       case 0x14:
228         return AMD_BOBCAT;
229       case 0x15:
230         return AMD_BULLDOZER;
231       case 0x16:
232         return AMD_JAGUAR;
233       case 0x17:
234         return AMD_ZEN;
235       default:
236         return X86_UNKNOWN;
237     }
238   }
239   return X86_UNKNOWN;
240 }
241
242 static void SetString(const uint32_t max_cpuid_ext_leaf, const uint32_t leaf_id,
243                       char* buffer) {
244   const Leaf leaf = SafeCpuId(max_cpuid_ext_leaf, leaf_id);
245   // We allow calling memcpy from SetString which is only called when requesting
246   // X86BrandString.
247   memcpy(buffer, &leaf, sizeof(Leaf));
248 }
249
250 void FillX86BrandString(char brand_string[49]) {
251   const Leaf leaf_ext_0 = CpuId(0x80000000);
252   const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax;
253   SetString(max_cpuid_leaf_ext, 0x80000002, brand_string);
254   SetString(max_cpuid_leaf_ext, 0x80000003, brand_string + 16);
255   SetString(max_cpuid_leaf_ext, 0x80000004, brand_string + 32);
256   brand_string[48] = '\0';
257 }
258
259 ////////////////////////////////////////////////////////////////////////////////
260 // Introspection functions
261
262 int GetX86FeaturesEnumValue(const X86Features* features,
263                             X86FeaturesEnum value) {
264   switch (value) {
265     case X86_AES:
266       return features->aes;
267     case X86_ERMS:
268       return features->erms;
269     case X86_F16C:
270       return features->f16c;
271     case X86_FMA3:
272       return features->fma3;
273     case X86_VPCLMULQDQ:
274       return features->vpclmulqdq;
275     case X86_BMI1:
276       return features->bmi1;
277     case X86_BMI2:
278       return features->bmi2;
279     case X86_SSSE3:
280       return features->ssse3;
281     case X86_SSE4_1:
282       return features->sse4_1;
283     case X86_SSE4_2:
284       return features->sse4_2;
285     case X86_AVX:
286       return features->avx;
287     case X86_AVX2:
288       return features->avx2;
289     case X86_AVX512F:
290       return features->avx512f;
291     case X86_AVX512CD:
292       return features->avx512cd;
293     case X86_AVX512ER:
294       return features->avx512er;
295     case X86_AVX512PF:
296       return features->avx512pf;
297     case X86_AVX512BW:
298       return features->avx512bw;
299     case X86_AVX512DQ:
300       return features->avx512dq;
301     case X86_AVX512VL:
302       return features->avx512vl;
303     case X86_AVX512IFMA:
304       return features->avx512ifma;
305     case X86_AVX512VBMI:
306       return features->avx512vbmi;
307     case X86_AVX512VBMI2:
308       return features->avx512vbmi2;
309     case X86_AVX512VNNI:
310       return features->avx512vnni;
311     case X86_AVX512BITALG:
312       return features->avx512bitalg;
313     case X86_AVX512VPOPCNTDQ:
314       return features->avx512vpopcntdq;
315     case X86_AVX512_4VNNIW:
316       return features->avx512_4vnniw;
317     case X86_AVX512_4VBMI2:
318       return features->avx512_4vbmi2;
319     case X86_SMX:
320       return features->smx;
321     case X86_SGX:
322       return features->sgx;
323     case X86_CX16:
324       return features->cx16;
325     case X86_LAST_:
326       break;
327   }
328   return false;
329 }
330
331 const char* GetX86FeaturesEnumName(X86FeaturesEnum value) {
332   switch (value) {
333     case X86_AES:
334       return "aes";
335     case X86_ERMS:
336       return "erms";
337     case X86_F16C:
338       return "f16c";
339     case X86_FMA3:
340       return "fma3";
341     case X86_VPCLMULQDQ:
342       return "vpclmulqdq";
343     case X86_BMI1:
344       return "bmi1";
345     case X86_BMI2:
346       return "bmi2";
347     case X86_SSSE3:
348       return "ssse3";
349     case X86_SSE4_1:
350       return "sse4_1";
351     case X86_SSE4_2:
352       return "sse4_2";
353     case X86_AVX:
354       return "avx";
355     case X86_AVX2:
356       return "avx2";
357     case X86_AVX512F:
358       return "avx512f";
359     case X86_AVX512CD:
360       return "avx512cd";
361     case X86_AVX512ER:
362       return "avx512er";
363     case X86_AVX512PF:
364       return "avx512pf";
365     case X86_AVX512BW:
366       return "avx512bw";
367     case X86_AVX512DQ:
368       return "avx512dq";
369     case X86_AVX512VL:
370       return "avx512vl";
371     case X86_AVX512IFMA:
372       return "avx512ifma";
373     case X86_AVX512VBMI:
374       return "avx512vbmi";
375     case X86_AVX512VBMI2:
376       return "avx512vbmi2";
377     case X86_AVX512VNNI:
378       return "avx512vnni";
379     case X86_AVX512BITALG:
380       return "avx512bitalg";
381     case X86_AVX512VPOPCNTDQ:
382       return "avx512vpopcntdq";
383     case X86_AVX512_4VNNIW:
384       return "avx512_4vnniw";
385     case X86_AVX512_4VBMI2:
386       return "avx512_4vbmi2";
387     case X86_SMX:
388       return "smx";
389     case X86_SGX:
390       return "sgx";
391     case X86_CX16:
392       return "cx16";
393     case X86_LAST_:
394       break;
395   }
396   return "unknown_feature";
397 }
398
399 const char* GetX86MicroarchitectureName(X86Microarchitecture uarch) {
400   switch (uarch) {
401     case X86_UNKNOWN:
402       return "X86_UNKNOWN";
403     case INTEL_CORE:
404       return "INTEL_CORE";
405     case INTEL_PNR:
406       return "INTEL_PNR";
407     case INTEL_NHM:
408       return "INTEL_NHM";
409     case INTEL_ATOM_BNL:
410       return "INTEL_ATOM_BNL";
411     case INTEL_WSM:
412       return "INTEL_WSM";
413     case INTEL_SNB:
414       return "INTEL_SNB";
415     case INTEL_IVB:
416       return "INTEL_IVB";
417     case INTEL_ATOM_SMT:
418       return "INTEL_ATOM_SMT";
419     case INTEL_HSW:
420       return "INTEL_HSW";
421     case INTEL_BDW:
422       return "INTEL_BDW";
423     case INTEL_SKL:
424       return "INTEL_SKL";
425     case INTEL_ATOM_GMT:
426       return "INTEL_ATOM_GMT";
427     case INTEL_KBL:
428       return "INTEL_KBL";
429     case INTEL_CFL:
430       return "INTEL_CFL";
431     case INTEL_CNL:
432       return "INTEL_CNL";
433     case AMD_HAMMER:
434       return "AMD_HAMMER";
435     case AMD_K10:
436       return "AMD_K10";
437     case AMD_BOBCAT:
438       return "AMD_BOBCAT";
439     case AMD_BULLDOZER:
440       return "AMD_BULLDOZER";
441     case AMD_JAGUAR:
442       return "AMD_JAGUAR";
443     case AMD_ZEN:
444       return "AMD_ZEN";
445   }
446   return "unknown microarchitecture";
447 }