@@ -18,6 +18,9 @@ pub enum NormalizeCpuidError {
18
18
/// Failed to passthrough cache topology.
19
19
#[ error( "Failed to passthrough cache topology: {0}" ) ]
20
20
PassthroughCacheTopology ( #[ from] PassthroughCacheTopologyError ) ,
21
+ /// Missing leaf 0x7 / subleaf 0.
22
+ #[ error( "Missing leaf 0x7 / subleaf 0." ) ]
23
+ MissingLeaf0x7Subleaf0 ,
21
24
/// Missing leaf 0x80000000.
22
25
#[ error( "Missing leaf 0x80000000." ) ]
23
26
MissingLeaf0x80000000 ,
@@ -119,6 +122,7 @@ impl super::AmdCpuid {
119
122
cpus_per_core : u8 ,
120
123
) -> Result < ( ) , NormalizeCpuidError > {
121
124
self . passthrough_cache_topology ( ) ?;
125
+ self . update_structured_extended_entry ( ) ?;
122
126
self . update_largest_extended_fn_entry ( ) ?;
123
127
self . update_extended_feature_fn_entry ( ) ?;
124
128
self . update_amd_feature_entry ( cpu_count) ?;
@@ -227,6 +231,20 @@ impl super::AmdCpuid {
227
231
Ok ( ( ) )
228
232
}
229
233
234
+ // Update structured extended feature entry.
235
+ fn update_structured_extended_entry ( & mut self ) -> Result < ( ) , NormalizeCpuidError > {
236
+ let leaf_7_subleaf_0 = self
237
+ . get_mut ( & CpuidKey :: subleaf ( 0x7 , 0x0 ) )
238
+ . ok_or ( NormalizeCpuidError :: MissingLeaf0x7Subleaf0 ) ?;
239
+
240
+ // According to AMD64 Architecture Programmer’s Manual, IA32_ARCH_CAPABILITIES MSR is not
241
+ // available on AMD. The availability of IA32_ARCH_CAPABILITIES MSR is controlled via
242
+ // CPUID.07H(ECX=0):EDX[bit 29]. KVM sets this bit no matter what but this feature is not
243
+ // supported by hardware.
244
+ set_bit ( & mut leaf_7_subleaf_0. result . edx , 29 , false ) ;
245
+ Ok ( ( ) )
246
+ }
247
+
230
248
/// Update AMD feature entry.
231
249
#[ allow( clippy:: unwrap_used, clippy:: unwrap_in_result) ]
232
250
fn update_amd_feature_entry ( & mut self , cpu_count : u8 ) -> Result < ( ) , FeatureEntryError > {
@@ -408,3 +426,57 @@ impl super::AmdCpuid {
408
426
Ok ( ( ) )
409
427
}
410
428
}
429
+
430
+ #[ cfg( test) ]
431
+ mod tests {
432
+
433
+ use std:: collections:: BTreeMap ;
434
+
435
+ use super :: * ;
436
+ use crate :: guest_config:: cpuid:: AmdCpuid ;
437
+
438
+ #[ test]
439
+ fn test_update_structured_extended_entry_invalid ( ) {
440
+ // `update_structured_extended_entry()` should exit with MissingLeaf0x7Subleaf0 error for
441
+ // CPUID lacking leaf 0x7 / subleaf 0.
442
+ let mut cpuid = AmdCpuid ( BTreeMap :: new ( ) ) ;
443
+ assert_eq ! (
444
+ cpuid. update_structured_extended_entry( ) . unwrap_err( ) ,
445
+ NormalizeCpuidError :: MissingLeaf0x7Subleaf0
446
+ ) ;
447
+ }
448
+
449
+ #[ test]
450
+ fn test_update_structured_extended_entry_valid ( ) {
451
+ // `update_structured_extended_entry()` should succeed for CPUID having leaf 0x7 / subleaf
452
+ // 0, and bit 29 of EDX (IA32_ARCH_CAPABILITIES MSR enumeration) should be disabled.
453
+ let mut cpuid = AmdCpuid ( BTreeMap :: from ( [ (
454
+ CpuidKey {
455
+ leaf : 0x7 ,
456
+ subleaf : 0x0 ,
457
+ } ,
458
+ CpuidEntry {
459
+ flags : KvmCpuidFlags :: SIGNIFICANT_INDEX ,
460
+ result : CpuidRegisters {
461
+ eax : 0 ,
462
+ ebx : 0 ,
463
+ ecx : 0 ,
464
+ edx : u32:: MAX ,
465
+ } ,
466
+ } ,
467
+ ) ] ) ) ;
468
+ assert ! ( cpuid. update_structured_extended_entry( ) . is_ok( ) ) ;
469
+ assert_eq ! (
470
+ cpuid
471
+ . get( & CpuidKey {
472
+ leaf: 0x7 ,
473
+ subleaf: 0x0
474
+ } )
475
+ . unwrap( )
476
+ . result
477
+ . edx
478
+ & ( 1 << 29 ) ,
479
+ 0
480
+ ) ;
481
+ }
482
+ }
0 commit comments