Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/symcrypt/lib/cpuid.c
15010 views
1
//
2
// cpuid.c code for CPU feature detection based on CPUID
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
7
8
#include "precomp.h"
9
10
#if (SYMCRYPT_CPU_ARM | SYMCRYPT_CPU_ARM64) & SYMCRYPT_MS_VC
11
#include <excpt.h>
12
#endif
13
14
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
15
16
#ifdef __clang__
17
#pragma clang attribute push (__attribute__((target("xsave"))), apply_to=function)
18
#else
19
#pragma GCC push_options
20
#pragma GCC target("xsave")
21
#endif
22
23
//
24
// RDRAND availability is signaled by CPUID.1.ecx[30]
25
// PCLMULQDQ availability is signaled by CPUID.1.ecx[1]
26
// AES_NI availability is signaled by CPUID.1.ecx[25]
27
// SSSE3 availability is signaled by CPUID.1.ecx[9]
28
// SSE3 availability is signaled by CPUID.1.ecx[0]
29
// SSE2 availability is signaled by CPUID.1.edx[26]
30
//
31
32
#define CPUID_1_ECX_RDRAND_BIT 30
33
#define CPUID_1_ECX_PCLMULQDQ_BIT 1
34
#define CPUID_1_ECX_AESNI_BIT 25
35
#define CPUID_1_ECX_SSSE3_BIT 9
36
#define CPUID_1_ECX_SSE3_BIT 0
37
#define CPUID_1_EDX_SSE2_BIT 26
38
#define CPUID_1_EDX_SSE_BIT 25
39
#define CPUID_1_ECX_AVX_BIT 28
40
#define CPUID_1_ECX_CMPXCHG16B_BIT 13
41
#define CPUID_70_EBX_AVX2_BIT 5
42
#define CPUID_70_EBX_RDSEED_BIT 18
43
#define CPUID_70_EBX_SHANI_BIT 29
44
#define CPUID_70_EBX_ADX_BIT 19
45
#define CPUID_70_EBX_BMI2_BIT 8
46
#define CPUID_70_EBX_AVX512F_BIT 16
47
#define CPUID_70_EBX_AVX512BW_BIT 30
48
#define CPUID_70_EBX_AVX512DQ_BIT 17
49
#define CPUID_70_EBX_AVX512VL_BIT 31
50
#define CPUID_70_ECX_VAES_BIT 9
51
#define CPUID_70_ECX_VPCLMULQDQ_BIT 10
52
53
54
#define CPUID_1_ECX_OSXSAVE_BIT 27
55
56
typedef struct _CPUID_BIT_INFO {
57
BYTE leaf;
58
BYTE word;
59
BYTE bitno;
60
SYMCRYPT_CPU_FEATURES requiredBy;
61
} CPUID_BIT_INFO;
62
63
#define WORD_EAX 0
64
#define WORD_EBX 1
65
#define WORD_ECX 2
66
#define WORD_EDX 3
67
68
int g_SymCryptCpuid1[4]; // We cache the results of CPUID(1) to help diagnose CPU detection errors
69
70
const
71
CPUID_BIT_INFO cpuidBitInfo[] = {
72
{1, WORD_ECX, CPUID_1_ECX_RDRAND_BIT, SYMCRYPT_CPU_FEATURE_RDRAND },
73
{1, WORD_ECX, CPUID_1_ECX_PCLMULQDQ_BIT, SYMCRYPT_CPU_FEATURE_PCLMULQDQ },
74
{1, WORD_ECX, CPUID_1_ECX_AESNI_BIT, SYMCRYPT_CPU_FEATURE_AESNI },
75
{1, WORD_EDX, CPUID_1_EDX_SSE_BIT, SYMCRYPT_CPU_FEATURE_SSE2 | SYMCRYPT_CPU_FEATURE_SSSE3 },
76
{1, WORD_EDX, CPUID_1_EDX_SSE2_BIT, SYMCRYPT_CPU_FEATURE_SSE2 | SYMCRYPT_CPU_FEATURE_SSSE3 },
77
{1, WORD_ECX, CPUID_1_ECX_SSE3_BIT, SYMCRYPT_CPU_FEATURE_SSSE3 },
78
{1, WORD_ECX, CPUID_1_ECX_SSSE3_BIT, SYMCRYPT_CPU_FEATURE_SSSE3 },
79
{1, WORD_ECX, CPUID_1_ECX_AVX_BIT, SYMCRYPT_CPU_FEATURE_AVX2 },
80
{1, WORD_ECX, CPUID_1_ECX_CMPXCHG16B_BIT, SYMCRYPT_CPU_FEATURE_CMPXCHG16B },
81
{7, WORD_EBX, CPUID_70_EBX_AVX2_BIT, SYMCRYPT_CPU_FEATURE_AVX2 },
82
{7, WORD_EBX, CPUID_70_EBX_RDSEED_BIT, SYMCRYPT_CPU_FEATURE_RDSEED },
83
{7, WORD_EBX, CPUID_70_EBX_SHANI_BIT, SYMCRYPT_CPU_FEATURE_SHANI },
84
{7, WORD_EBX, CPUID_70_EBX_ADX_BIT, SYMCRYPT_CPU_FEATURE_ADX },
85
{7, WORD_EBX, CPUID_70_EBX_BMI2_BIT, SYMCRYPT_CPU_FEATURE_BMI2 },
86
{7, WORD_EBX, CPUID_70_EBX_AVX512F_BIT, SYMCRYPT_CPU_FEATURE_AVX512 },
87
{7, WORD_EBX, CPUID_70_EBX_AVX512VL_BIT, SYMCRYPT_CPU_FEATURE_AVX512 },
88
{7, WORD_EBX, CPUID_70_EBX_AVX512BW_BIT, SYMCRYPT_CPU_FEATURE_AVX512 },
89
{7, WORD_EBX, CPUID_70_EBX_AVX512DQ_BIT, SYMCRYPT_CPU_FEATURE_AVX512 },
90
{7, WORD_ECX, CPUID_70_ECX_VAES_BIT, SYMCRYPT_CPU_FEATURE_VAES },
91
{7, WORD_ECX, CPUID_70_ECX_VPCLMULQDQ_BIT, SYMCRYPT_CPU_FEATURE_VAES },
92
};
93
94
VOID
95
SYMCRYPT_CALL
96
SymCryptDetectCpuFeaturesByCpuid( UINT32 flags )
97
{
98
UINT32 result;
99
int CPUInfo[4];
100
int InfoType;
101
int maxInfoType;
102
int i;
103
BOOLEAN allowYmm, allowZmm;
104
INT64 xGetBvResult;
105
106
//
107
// Mark all features as present (the result bits indicate not-present, so set the features we know to 0).
108
//
109
result = ~ (UINT32)(
110
SYMCRYPT_CPU_FEATURE_SSE2 |
111
SYMCRYPT_CPU_FEATURE_SSSE3 |
112
SYMCRYPT_CPU_FEATURE_AESNI |
113
SYMCRYPT_CPU_FEATURE_PCLMULQDQ |
114
SYMCRYPT_CPU_FEATURE_AVX2 |
115
SYMCRYPT_CPU_FEATURE_SHANI |
116
SYMCRYPT_CPU_FEATURE_BMI2 |
117
SYMCRYPT_CPU_FEATURE_ADX |
118
SYMCRYPT_CPU_FEATURE_RDRAND |
119
SYMCRYPT_CPU_FEATURE_RDSEED |
120
SYMCRYPT_CPU_FEATURE_AVX512 |
121
SYMCRYPT_CPU_FEATURE_VAES |
122
SYMCRYPT_CPU_FEATURE_CMPXCHG16B
123
);
124
125
// InfoType holds the function id of previous cpuid
126
// so we don't have to repeatedly invoke cpuid.
127
InfoType = 0;
128
SymCryptCpuidExFunc( CPUInfo, InfoType, 0 );
129
maxInfoType = CPUInfo[WORD_EAX];
130
131
for( i=0; i< sizeof( cpuidBitInfo ) / sizeof( *cpuidBitInfo ); i++ )
132
{
133
if( cpuidBitInfo[i].leaf != InfoType )
134
{
135
InfoType = cpuidBitInfo[i].leaf;
136
SymCryptCpuidExFunc( CPUInfo, InfoType, 0 );
137
}
138
if( cpuidBitInfo[i].leaf > maxInfoType || (CPUInfo[ cpuidBitInfo[i].word ] & (1UL << cpuidBitInfo[i].bitno) ) == 0 )
139
{
140
result |= cpuidBitInfo[i].requiredBy;
141
}
142
}
143
144
if( (flags & SYMCRYPT_CPUID_DETECT_FLAG_CHECK_OS_SUPPORT_FOR_YMM) != 0 )
145
{
146
//
147
// Check for OS support of the YMM registers.
148
// This detection is optional in any environment because some environments are single-threaded, and
149
// OS support is not required. (E.g. Boot library.)
150
//
151
// We use the following logic:
152
// Check that the OSXSAVE bit is 1, which means we can use XGETBV
153
// Use XGETBV and check that XCR0[2:1] = '11b' signaling that both XMM and YMM are enabled by OS
154
// Note that we only disable the AVX2 usage; AESNI & XMM registers are used independent of OS support, because
155
// all our (known) OSes have it.
156
//
157
allowYmm = FALSE;
158
allowZmm = FALSE;
159
SymCryptCpuidExFunc( CPUInfo, 1, 0 );
160
161
if( (CPUInfo[WORD_ECX] & (1 << CPUID_1_ECX_OSXSAVE_BIT)) != 0 )
162
{
163
// OSXSAVE bit is set, we can use XGETBV
164
xGetBvResult = _xgetbv( _XCR_XFEATURE_ENABLED_MASK );
165
166
// Check that bits 1 and 2 are set, corresponding to the XMM and YMM register state
167
if( (xGetBvResult & 0x6) == 0x6)
168
{
169
allowYmm = TRUE;
170
171
//
172
// For AVX-512, also check that bits 5, 6, and 7 are set, corresponding to the
173
// opmask, ZMM (0-15), and ZMM (16-31) register states
174
// This follows the recommendation in the Intel 64 and IA-32 Architectures Software
175
// Developer's Manual, Volume 1, 15.3 / 15.4.
176
//
177
// It seems plausible that on some system the OS would not support save/restore of
178
// AVX-512 state, but use of AVX-512VL instructions on Ymm or Xmm registers would be
179
// OK, however Intel explicitly suggests that we should only use AVX512-VL if the
180
// support is indicated by xgetbv, so we use the same logic as for AVX2 (our
181
// SymCrypt feature indicates both CPU support, and OS support for saving/restoring
182
// the extended state)
183
//
184
if( (xGetBvResult & 0xe0) == 0xe0)
185
{
186
allowZmm = TRUE;
187
}
188
}
189
}
190
191
if( !allowYmm )
192
{
193
// Disallow the AVX2-dependent code because we don't have OS YMM support.
194
result |= SYMCRYPT_CPU_FEATURE_AVX2;
195
}
196
197
if( !allowZmm )
198
{
199
// Disallow any AVX512-dependent code because we don't have OS ZMM support.
200
// Note that not all AVX-512 dependent code will need to save/restore ZMM state, but we
201
// do not support AVX-512 instructions (even acting on YMM or XMM registers), unless the
202
// OS indicates support via XCR0
203
result |= SYMCRYPT_CPU_FEATURE_AVX512;
204
}
205
}
206
207
208
if( (result & SYMCRYPT_CPU_FEATURE_AESNI) == 0 ) // thus, if AES-NI is present according to CPUID
209
{
210
//
211
// In Win7 Beta we had an interesting crash bucket.
212
// It only occurred on the AsusTek A6K line of laptops which sometimes
213
// set the cpuid AES-NI bit (but not always). This leads to a crash as
214
// we start using AES instructions that don't exist on those machines.
215
//
216
// I found on-line reviews for the A6K line from december 2005 so it was launched around
217
// that time.
218
//
219
// These laptops all have AMD CPUs, so we fix it by locking out the particular AMD CPUs
220
// families that don't have AES-NI anyway.
221
//
222
// We really shouldn't need this logic, and it only slows things down.
223
// We should be able to remove it at some point in the future.
224
//
225
// At AMD's recommendation, we use the logic below.
226
// The AMD engineers reviewed this code to ensure we don't lock out future CPUs
227
// that will have AES-NI.
228
//
229
SymCryptCpuidExFunc( CPUInfo, 0, 0 );
230
if( CPUInfo[WORD_EBX] == 'htuA'
231
&& CPUInfo[WORD_ECX] == 'DMAc'
232
&& CPUInfo[WORD_EDX] == 'itne' )
233
{
234
//
235
// We have an AMD cpu, check the family.
236
//
237
UINT32 baseFamily;
238
UINT32 extFamily;
239
UINT32 family;
240
241
//
242
// Extract the base family and extended family values, and combine them to the full
243
// family value.
244
//
245
SymCryptCpuidExFunc( CPUInfo, 1, 0 );
246
247
baseFamily = (CPUInfo[WORD_EAX] >> 8) & 0xf;
248
249
extFamily = (CPUInfo[WORD_EAX] >> 20) & 0xff;
250
251
if( baseFamily < 0xf )
252
{
253
family = baseFamily;
254
} else {
255
family = baseFamily + extFamily;
256
}
257
258
//
259
// AMD will not implement the AES instruction set until family 0x15
260
//
261
if( family < 0x15 )
262
{
263
result |= SYMCRYPT_CPU_FEATURE_AESNI;
264
}
265
}
266
}
267
268
SymCryptCpuidExFunc( g_SymCryptCpuid1, 1, 0 ); // Keep cache of CPUID results for diagnosis
269
270
g_SymCryptCpuFeaturesNotPresent = (SYMCRYPT_CPU_FEATURES) result;
271
}
272
273
#ifdef __clang__
274
#pragma clang attribute pop
275
#else
276
#pragma GCC pop_options
277
#endif
278
279
#elif SYMCRYPT_CPU_ARM
280
281
#define CP15_ISAR5 15, 0, 0, 2, 5 // Instruction Set Attribute Register 5
282
283
#define READ_ARM_FEATURE(_FeatureRegister, _Index) \
284
(((ULONG)_MoveFromCoprocessor(_FeatureRegister) >> ((_Index) * 4)) & 0xF)
285
286
#define ISAR5_AES 1
287
#define ISAR5_AES_AESE 1
288
#define ISAR5_AES_PMULL 2
289
290
#define ISAR5_SHA2 3
291
#define ISAR5_SHA2_SHA256H 1
292
293
#define ISAR5_CRC32 4
294
#define ISAR5_CRC32_IMP 1
295
296
VOID
297
SYMCRYPT_CALL
298
SymCryptDetectCpuFeaturesFromRegisters(void)
299
{
300
UINT32 result;
301
302
#if 0 // We currently do not use any neon crypto features on ARM code, so no detection needed.
303
304
//
305
// We start with a result that allows everything.
306
// This makes the code simpler when you have one CPU feature flag that disables multiple feature bits.
307
//
308
result = ~ (UINT32)(
309
SYMCRYPT_CPU_FEATURE_NEON |
310
SYMCRYPT_CPU_FEATURE_NEON_AES |
311
SYMCRYPT_CPU_FEATURE_NEON_PMULL |
312
SYMCRYPT_CPU_FEATURE_NEON_SHA256
313
);
314
315
//
316
// Reading the status registers might fail, so we use a try block.
317
//
318
try {
319
320
if( READ_ARM_FEATURE(CP15_ISAR5, ISAR5_AES) < ISAR5_AES_AESE )
321
{
322
result |= SYMCRYPT_CPU_FEATURE_NEON_AES;
323
}
324
325
if( READ_ARM_FEATURE(CP15_ISAR5, ISAR5_AES) < ISAR5_AES_PMULL )
326
{
327
result |= SYMCRYPT_CPU_FEATURE_NEON_PMULL;
328
}
329
330
if( READ_ARM_FEATURE(CP15_ISAR5, ISAR5_SHA2) < ISAR5_SHA2_SHA256H )
331
{
332
result |= SYMCRYPT_CPU_FEATURE_NEON_SHA256;
333
}
334
335
} except(EXCEPTION_EXECUTE_HANDLER) {
336
//
337
// Something went wrong reading the registers; disable all the crypto extensions leaving only the standard NEON registers available.
338
//
339
result |= SYMCRYPT_CPU_FEATURE_NEON_AES | SYMCRYPT_CPU_FEATURE_NEON_PMULL | SYMCRYPT_CPU_FEATURE_NEON_SHA256;
340
}
341
#endif
342
//
343
// For now we ignore the new instructions in ARM until we can get clarity on how to detect Arm32-on-Arm64.
344
//
345
result = ~(UINT32)SYMCRYPT_CPU_FEATURE_NEON;
346
347
g_SymCryptCpuFeaturesNotPresent = (SYMCRYPT_CPU_FEATURES) result;
348
}
349
350
351
#elif SYMCRYPT_CPU_ARM64 && !SYMCRYPT_PLATFORM_WINE
352
353
354
#define ARM64_SYSREG(op0, op1, crn, crm, op2) \
355
( ((op0 & 1) << 14) | \
356
((op1 & 7) << 11) | \
357
((crn & 15) << 7) | \
358
((crm & 15) << 3) | \
359
((op2 & 7) << 0) )
360
361
#define ARM64_ID_AA64ISAR0_EL1 ARM64_SYSREG(3,0, 0, 6,0) // ISA Feature Register 0
362
363
#define ISAR0_AES 1
364
#define ISAR0_AES_NI 0
365
#define ISAR0_AES_INSTRUCTIONS 1
366
#define ISAR0_AES_PLUS_PMULL64 2
367
368
#define ISAR0_SHA2 3
369
#define ISAR0_SHA2_NI 0
370
#define ISAR0_SHA2_INSTRUCTIONS 1
371
372
#define ISAR0_CRC32 4
373
#define ISAR0_CRC32_NI 0
374
#define ISAR0_CRC32_INSTRUCTIONS 1
375
376
#define READ_ARM64_FEATURE(_FeatureRegister, _Index) \
377
(((ULONG64)_ReadStatusReg(_FeatureRegister) >> ((_Index) * 4)) & 0xF)
378
379
VOID
380
SYMCRYPT_CALL
381
SymCryptDetectCpuFeaturesFromRegisters(void)
382
{
383
UINT32 result;
384
385
result = ~ (UINT32)(
386
SYMCRYPT_CPU_FEATURE_NEON |
387
SYMCRYPT_CPU_FEATURE_NEON_AES |
388
SYMCRYPT_CPU_FEATURE_NEON_PMULL |
389
SYMCRYPT_CPU_FEATURE_NEON_SHA256
390
);
391
392
#if SYMCRYPT_MS_VC
393
__try {
394
395
if( READ_ARM64_FEATURE(ARM64_ID_AA64ISAR0_EL1, ISAR0_AES) < ISAR0_AES_INSTRUCTIONS )
396
{
397
result |= SYMCRYPT_CPU_FEATURE_NEON_AES;
398
}
399
400
if( READ_ARM64_FEATURE(ARM64_ID_AA64ISAR0_EL1, ISAR0_AES) < ISAR0_AES_PLUS_PMULL64 )
401
{
402
result |= SYMCRYPT_CPU_FEATURE_NEON_PMULL;
403
}
404
405
if( READ_ARM64_FEATURE(ARM64_ID_AA64ISAR0_EL1, ISAR0_SHA2) < ISAR0_SHA2_INSTRUCTIONS )
406
{
407
result |= SYMCRYPT_CPU_FEATURE_NEON_SHA256;
408
}
409
410
g_SymCryptCpuFeaturesNotPresent = (SYMCRYPT_CPU_FEATURES) result;
411
412
} __except(EXCEPTION_EXECUTE_HANDLER) {
413
; //NOTHING;
414
}
415
#endif
416
417
}
418
419
#endif // CPU arch selection
420
421