@@ -980,15 +980,41 @@ impl Vmm {
980
980
Ok ( ( ) )
981
981
}
982
982
983
- fn start_vcpus (
983
+ // On aarch64, the vCPUs need to be created (i.e call KVM_CREATE_VCPU)_and configured before
984
+ // setting up the IRQ chip because the `KVM_CREATE_VCPU` ioctl will return error if the IRQCHIP
985
+ // was already initialized.
986
+ // Search for `kvm_arch_vcpu_create` in arch/arm/kvm/arm.c.
987
+ fn create_vcpus (
984
988
& mut self ,
985
989
entry_addr : GuestAddress ,
986
- ) -> std:: result:: Result < ( ) , StartMicrovmError > {
990
+ ) -> std:: result:: Result < Vec < Vcpu > , StartMicrovmError > {
991
+ let vcpu_count = self
992
+ . vm_config
993
+ . vcpu_count
994
+ . ok_or ( StartMicrovmError :: VcpusNotConfigured ) ?;
995
+ let mut vcpus = Vec :: with_capacity ( vcpu_count as usize ) ;
996
+ for cpu_id in 0 ..vcpu_count {
997
+ let mut vcpu = Vcpu :: new ( cpu_id, & self . vm ) . map_err ( StartMicrovmError :: Vcpu ) ?;
998
+ #[ cfg( target_arch = "x86_64" ) ]
999
+ vcpu. configure ( & self . vm_config , entry_addr, & self . vm )
1000
+ . map_err ( StartMicrovmError :: VcpuConfigure ) ?;
1001
+ vcpus. push ( vcpu) ;
1002
+ }
1003
+ Ok ( vcpus)
1004
+ }
1005
+
1006
+ fn start_vcpus ( & mut self , mut vcpus : Vec < Vcpu > ) -> std:: result:: Result < ( ) , StartMicrovmError > {
987
1007
// vm_config has a default value for vcpu_count.
988
1008
let vcpu_count = self
989
1009
. vm_config
990
1010
. vcpu_count
991
1011
. ok_or ( StartMicrovmError :: VcpusNotConfigured ) ?;
1012
+ assert_eq ! (
1013
+ vcpus. len( ) ,
1014
+ vcpu_count as usize ,
1015
+ "The number of vCPU fds is corrupted!"
1016
+ ) ;
1017
+
992
1018
self . vcpu_handles = Some ( Vec :: with_capacity ( vcpu_count as usize ) ) ;
993
1019
// It is safe to unwrap since it's set just above.
994
1020
let vcpu_handles = self . vcpu_handles . as_mut ( ) . unwrap ( ) ;
@@ -1014,15 +1040,14 @@ impl Vmm {
1014
1040
. get_reset_evt_clone ( )
1015
1041
. map_err ( |_| StartMicrovmError :: EventFd ) ?;
1016
1042
1017
- let mut vcpu = Vcpu :: new ( cpu_id, & self . vm ) . map_err ( StartMicrovmError :: Vcpu ) ?;
1043
+ // `unwrap` is safe since we are asserting that the `vcpu_count` is equal to the number
1044
+ // of items of `vcpus` vector.
1045
+ let vcpu = vcpus. pop ( ) . unwrap ( ) ;
1046
+
1018
1047
let seccomp_level = self . seccomp_level ;
1019
1048
// It is safe to unwrap the ht_enabled flag because the machine configure
1020
1049
// has default values for all fields.
1021
1050
1022
- #[ cfg( target_arch = "x86_64" ) ]
1023
- vcpu. configure ( & self . vm_config , entry_addr, & self . vm )
1024
- . map_err ( StartMicrovmError :: VcpuConfigure ) ?;
1025
-
1026
1051
vcpu_handles. push (
1027
1052
thread:: Builder :: new ( )
1028
1053
. name ( format ! ( "fc_vcpu{}" , cpu_id) )
@@ -1256,9 +1281,13 @@ impl Vmm {
1256
1281
1257
1282
self . register_events ( )
1258
1283
. map_err ( |e| VmmActionError :: StartMicrovm ( ErrorKind :: Internal , e) ) ?;
1259
- self . start_vcpus ( entry_addr)
1284
+
1285
+ let vcpus = self
1286
+ . create_vcpus ( entry_addr)
1260
1287
. map_err ( |e| VmmActionError :: StartMicrovm ( ErrorKind :: Internal , e) ) ?;
1261
1288
1289
+ self . start_vcpus ( vcpus)
1290
+ . map_err ( |e| VmmActionError :: StartMicrovm ( ErrorKind :: Internal , e) ) ?;
1262
1291
// Use expect() to crash if the other thread poisoned this lock.
1263
1292
self . shared_info
1264
1293
. write ( )
@@ -2988,4 +3017,30 @@ mod tests {
2988
3017
assert_eq ! ( vmm. get_dirty_page_count( ) , 0 ) ;
2989
3018
// Booting an actual guest and getting real data is covered by `kvm::tests::run_code_test`.
2990
3019
}
3020
+
3021
+ #[ cfg( target_arch = "x86_64" ) ]
3022
+ #[ test]
3023
+ fn test_create_vcpus ( ) {
3024
+ let mut vmm = create_vmm_object ( InstanceState :: Uninitialized ) ;
3025
+ vmm. default_kernel_config ( ) ;
3026
+
3027
+ assert ! ( vmm. init_guest_memory( ) . is_ok( ) ) ;
3028
+ assert ! ( vmm. guest_memory. is_some( ) ) ;
3029
+ let kvm = KvmContext :: new ( ) . unwrap ( ) ;
3030
+ let guest_mem = vmm. guest_memory . clone ( ) . unwrap ( ) ;
3031
+
3032
+ vmm. vm
3033
+ . memory_init ( guest_mem. clone ( ) , & kvm)
3034
+ . expect ( "Cannot initialize memory for test vm" ) ;
3035
+ assert ! ( vmm. vm. get_memory( ) . is_some( ) ) ;
3036
+ // `KVM_CREATE_VCPU` fails if the irqchip is not created beforehand. This is x86_64 speciifc.
3037
+ vmm. vm
3038
+ . setup_irqchip (
3039
+ & vmm. legacy_device_manager . com_evt_1_3 ,
3040
+ & vmm. legacy_device_manager . com_evt_2_4 ,
3041
+ & vmm. legacy_device_manager . kbd_evt ,
3042
+ )
3043
+ . expect ( "Cannot create IRQCHIP" ) ;
3044
+ assert ! ( vmm. create_vcpus( GuestAddress ( 0x0 ) ) . is_ok( ) ) ;
3045
+ }
2991
3046
}
0 commit comments