@@ -132,6 +132,10 @@ macro_rules! __unstable_detect_feature {
132
132
$crate:: vendor:: __unstable_detect_feature(
133
133
$crate:: vendor:: __Feature:: popcnt{ } )
134
134
} ;
135
+ ( "fxsr" ) => {
136
+ $crate:: vendor:: __unstable_detect_feature(
137
+ $crate:: vendor:: __Feature:: fxsr{ } )
138
+ } ;
135
139
( "xsave" ) => {
136
140
$crate:: vendor:: __unstable_detect_feature(
137
141
$crate:: vendor:: __Feature:: xsave{ } )
@@ -212,6 +216,8 @@ pub enum __Feature {
212
216
tbm,
213
217
/// POPCNT (Population Count)
214
218
popcnt,
219
+ /// FXSR (Floating-point context fast save and restor)
220
+ fxsr,
215
221
/// XSAVE (Save Processor Extended States)
216
222
xsave,
217
223
/// XSAVEOPT (Save Processor Extended States Optimized)
@@ -325,24 +331,27 @@ pub fn detect_features() -> usize {
325
331
enable ( proc_info_ecx, 19 , __Feature:: sse4_1) ;
326
332
enable ( proc_info_ecx, 20 , __Feature:: sse4_2) ;
327
333
enable ( proc_info_ecx, 23 , __Feature:: popcnt) ;
334
+ enable ( proc_info_edx, 24 , __Feature:: fxsr) ;
328
335
enable ( proc_info_edx, 25 , __Feature:: sse) ;
329
336
enable ( proc_info_edx, 26 , __Feature:: sse2) ;
330
337
331
338
enable ( extended_features_ebx, 3 , __Feature:: bmi) ;
332
339
enable ( extended_features_ebx, 8 , __Feature:: bmi2) ;
333
340
334
341
// `XSAVE` and `AVX` support:
335
- if bit:: test ( proc_info_ecx as usize , 26 ) {
342
+ let cpu_xsave = bit:: test ( proc_info_ecx as usize , 26 ) ;
343
+ if cpu_xsave {
336
344
// 0. Here the CPU supports `XSAVE`.
337
345
338
346
// 1. Detect `OSXSAVE`, that is, whether the OS is AVX enabled and
339
347
// supports saving the state of the AVX/AVX2 vector registers on
340
348
// context-switches, see:
341
349
//
342
- // - https://software.intel.
343
- // com/en-us/blogs/2011/04/14/is-avx-enabled
344
- // - https://hg.mozilla.
345
- // org/mozilla-central/file/64bab5cbb9b6/mozglue/build/SSE.cpp#l190
350
+ // - [intel: is avx enabled?][is_avx_enabled],
351
+ // - [mozilla: sse.cpp][mozilla_sse_cpp].
352
+ //
353
+ // [is_avx_enabled]: https://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled
354
+ // [mozilla_sse_cpp]: https://hg.mozilla.org/mozilla-central/file/64bab5cbb9b6/mozglue/build/SSE.cpp#l190
346
355
let cpu_osxsave = bit:: test ( proc_info_ecx as usize , 27 ) ;
347
356
348
357
// 2. The OS must have signaled the CPU that it supports saving and
@@ -354,11 +363,34 @@ pub fn detect_features() -> usize {
354
363
let os_avx_support = xcr0 & 6 == 6 ;
355
364
let os_avx512_support = xcr0 & 224 == 224 ;
356
365
366
+ // Only if the OS and the CPU support saving/restoring the AVX
367
+ // registers we enable `xsave` support:
357
368
if cpu_osxsave && os_avx_support {
358
- // Only if the OS and the CPU support saving/restoring the AVX
359
- // registers we enable `xsave` support:
369
+ // See "13.3 ENABLING THE XSAVE FEATURE SET AND XSAVE-ENABLED
370
+ // FEATURES" in the "Intel® 64 and IA-32 Architectures Software
371
+ // Developer’s Manual, Volume 1: Basic Architecture":
372
+ //
373
+ // "Software enables the XSAVE feature set by setting
374
+ // CR4.OSXSAVE[bit 18] to 1 (e.g., with the MOV to CR4
375
+ // instruction). If this bit is 0, execution of any of XGETBV,
376
+ // XRSTOR, XRSTORS, XSAVE, XSAVEC, XSAVEOPT, XSAVES, and XSETBV
377
+ // causes an invalid-opcode exception (#UD)"
378
+ //
360
379
enable ( proc_info_ecx, 26 , __Feature:: xsave) ;
361
380
381
+ // For `xsaveopt`, `xsavec`, and `xsaves` we need to query:
382
+ // Processor Extended State Enumeration Sub-leaf (EAX = 0DH,
383
+ // ECX = 1):
384
+ if max_basic_leaf >= 0xd {
385
+ let CpuidResult {
386
+ eax : proc_extended_state1_eax,
387
+ ..
388
+ } = unsafe { __cpuid_count ( 0xd_u32 , 1 ) } ;
389
+ enable ( proc_extended_state1_eax, 0 , __Feature:: xsaveopt) ;
390
+ enable ( proc_extended_state1_eax, 1 , __Feature:: xsavec) ;
391
+ enable ( proc_extended_state1_eax, 3 , __Feature:: xsaves) ;
392
+ }
393
+
362
394
// And AVX/AVX2:
363
395
enable ( proc_info_ecx, 28 , __Feature:: avx) ;
364
396
enable ( extended_features_ebx, 5 , __Feature:: avx2) ;
@@ -382,18 +414,6 @@ pub fn detect_features() -> usize {
382
414
) ;
383
415
}
384
416
}
385
-
386
- // Processor Extended State Enumeration Sub-leaf
387
- // (EAX = 0DH, ECX = 1)
388
- if max_basic_leaf >= 0xd {
389
- let CpuidResult {
390
- eax : proc_extended_state1_eax,
391
- ..
392
- } = unsafe { __cpuid_count ( 0xd_u32 , 1 ) } ;
393
- enable ( proc_extended_state1_eax, 0 , __Feature:: xsaveopt) ;
394
- enable ( proc_extended_state1_eax, 1 , __Feature:: xsavec) ;
395
- enable ( proc_extended_state1_eax, 3 , __Feature:: xsaves) ;
396
- }
397
417
}
398
418
399
419
// This detects ABM on AMD CPUs and LZCNT on Intel CPUs.
@@ -448,10 +468,11 @@ mod tests {
448
468
println ! ( "tbm: {:?}" , cfg_feature_enabled!( "tbm" ) ) ;
449
469
println ! ( "popcnt: {:?}" , cfg_feature_enabled!( "popcnt" ) ) ;
450
470
println ! ( "lzcnt: {:?}" , cfg_feature_enabled!( "lzcnt" ) ) ;
451
- println ! ( "xsave {:?}" , cfg_feature_enabled!( "xsave" ) ) ;
452
- println ! ( "xsaveopt {:?}" , cfg_feature_enabled!( "xsaveopt" ) ) ;
453
- println ! ( "xsaves {:?}" , cfg_feature_enabled!( "xsaves" ) ) ;
454
- println ! ( "xsavec {:?}" , cfg_feature_enabled!( "xsavec" ) ) ;
471
+ println ! ( "fxsr: {:?}" , cfg_feature_enabled!( "fxsr" ) ) ;
472
+ println ! ( "xsave: {:?}" , cfg_feature_enabled!( "xsave" ) ) ;
473
+ println ! ( "xsaveopt: {:?}" , cfg_feature_enabled!( "xsaveopt" ) ) ;
474
+ println ! ( "xsaves: {:?}" , cfg_feature_enabled!( "xsaves" ) ) ;
475
+ println ! ( "xsavec: {:?}" , cfg_feature_enabled!( "xsavec" ) ) ;
455
476
}
456
477
457
478
#[ test]
0 commit comments