@@ -12,6 +12,9 @@ use transformer::common::use_host_cpuid_function;
1212
1313// Largest extended function. It has to be larger then 0x8000001d (Extended Cache Topology).
1414const LARGEST_EXTENDED_FN : u32 = 0x8000_001f ;
15+ // This value allows at most 64 logical threads within a package.
16+ // See also the documentation for leaf_0x80000008::ecx::THREAD_ID_SIZE_BITRANGE
17+ const THREAD_ID_MAX_SIZE : u32 = 6 ;
1518
1619pub fn update_structured_extended_entry (
1720 entry : & mut kvm_cpuid_entry2 ,
@@ -56,6 +59,22 @@ pub fn update_extended_feature_info_entry(
5659 Ok ( ( ) )
5760}
5861
62+ pub fn update_amd_features_entry (
63+ entry : & mut kvm_cpuid_entry2 ,
64+ vm_spec : & VmSpec ,
65+ ) -> Result < ( ) , Error > {
66+ use cpu_leaf:: leaf_0x80000008:: * ;
67+
68+ // We don't support more then 64 threads right now.
69+ // It's safe to put them all on the same processor.
70+ entry
71+ . ecx
72+ . write_bits_in_range ( & ecx:: THREAD_ID_SIZE_BITRANGE , THREAD_ID_MAX_SIZE )
73+ . write_bits_in_range ( & ecx:: NUM_THREADS_BITRANGE , u32:: from ( vm_spec. cpu_count - 1 ) ) ;
74+
75+ Ok ( ( ) )
76+ }
77+
5978pub fn update_extended_cache_topology_entry (
6079 entry : & mut kvm_cpuid_entry2 ,
6180 vm_spec : & VmSpec ,
@@ -78,6 +97,7 @@ impl CpuidTransformer for AmdCpuidTransformer {
7897 leaf_0x7:: LEAF_NUM => Some ( amd:: update_structured_extended_entry) ,
7998 leaf_0x80000000:: LEAF_NUM => Some ( amd:: update_largest_extended_fn_entry) ,
8099 leaf_0x80000001:: LEAF_NUM => Some ( amd:: update_extended_feature_info_entry) ,
100+ leaf_0x80000008:: LEAF_NUM => Some ( amd:: update_amd_features_entry) ,
81101 leaf_0x8000001d:: LEAF_NUM => Some ( amd:: update_extended_cache_topology_entry) ,
82102 0x8000_0002 ..=0x8000_0004 => Some ( common:: update_brand_string_entry) ,
83103 _ => None ,
@@ -169,6 +189,33 @@ mod test {
169189 assert_eq ! ( entry. ecx. read_bit( ecx:: TOPOEXT_INDEX ) , true ) ;
170190 }
171191
192+ fn check_update_amd_features_entry ( cpu_count : u8 , ht_enabled : bool ) {
193+ use cpu_leaf:: leaf_0x80000008:: * ;
194+
195+ let vm_spec = VmSpec :: new ( VENDOR_ID_AMD , 0 , cpu_count, ht_enabled) ;
196+ let mut entry = & mut kvm_cpuid_entry2 {
197+ function : LEAF_NUM ,
198+ index : 0 ,
199+ flags : 0 ,
200+ eax : 0 ,
201+ ebx : 0 ,
202+ ecx : 0 ,
203+ edx : 0 ,
204+ padding : [ 0 , 0 , 0 ] ,
205+ } ;
206+
207+ assert ! ( update_amd_features_entry( & mut entry, & vm_spec) . is_ok( ) ) ;
208+
209+ assert_eq ! (
210+ entry. ecx. read_bits_in_range( & ecx:: NUM_THREADS_BITRANGE ) ,
211+ u32 :: from( cpu_count - 1 )
212+ ) ;
213+ assert_eq ! (
214+ entry. ecx. read_bits_in_range( & ecx:: THREAD_ID_SIZE_BITRANGE ) ,
215+ THREAD_ID_MAX_SIZE
216+ ) ;
217+ }
218+
172219 #[ test]
173220 fn test_update_extended_cache_topology_entry ( ) {
174221 let vm_spec = VmSpec :: new ( VENDOR_ID_AMD , 0 , 1 , false ) ;
@@ -187,4 +234,24 @@ mod test {
187234
188235 assert_eq ! ( entry. flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX , 1 ) ;
189236 }
237+
238+ #[ test]
239+ fn test_1vcpu_ht_off ( ) {
240+ check_update_amd_features_entry ( 1 , false ) ;
241+ }
242+
243+ #[ test]
244+ fn test_1vcpu_ht_on ( ) {
245+ check_update_amd_features_entry ( 1 , true ) ;
246+ }
247+
248+ #[ test]
249+ fn test_2vcpu_ht_off ( ) {
250+ check_update_amd_features_entry ( 2 , false ) ;
251+ }
252+
253+ #[ test]
254+ fn test_2vcpu_ht_on ( ) {
255+ check_update_amd_features_entry ( 2 , true ) ;
256+ }
190257}
0 commit comments