22// SPDX-License-Identifier: Apache-2.0 
33
44use  std:: io:: { Seek ,  SeekFrom } ; 
5+ use  std:: sync:: { Arc ,  Mutex } ; 
56use  std:: thread; 
67use  std:: time:: Duration ; 
78
@@ -15,7 +16,9 @@ use vmm::rpc_interface::{
1516use  vmm:: seccomp:: get_empty_filters; 
1617use  vmm:: snapshot:: Snapshot ; 
1718use  vmm:: test_utils:: mock_resources:: { MockVmResources ,  NOISY_KERNEL_IMAGE } ; 
18- use  vmm:: test_utils:: { create_vmm,  default_vmm,  default_vmm_no_boot} ; 
19+ use  vmm:: test_utils:: { 
20+     create_vmm,  default_vmm,  default_vmm_no_boot,  default_vmm_pci,  default_vmm_pci_no_boot, 
21+ } ; 
1922use  vmm:: vmm_config:: balloon:: BalloonDeviceConfig ; 
2023use  vmm:: vmm_config:: boot_source:: BootSourceConfig ; 
2124use  vmm:: vmm_config:: drive:: BlockDeviceConfig ; 
@@ -26,9 +29,23 @@ use vmm::vmm_config::snapshot::{
2629    CreateSnapshotParams ,  LoadSnapshotParams ,  MemBackendConfig ,  MemBackendType ,  SnapshotType , 
2730} ; 
2831use  vmm:: vmm_config:: vsock:: VsockDeviceConfig ; 
29- use  vmm:: { DumpCpuConfigError ,  EventManager ,  FcExitCode } ; 
32+ use  vmm:: { DumpCpuConfigError ,  EventManager ,  FcExitCode ,   Vmm } ; 
3033use  vmm_sys_util:: tempfile:: TempFile ; 
3134
35+ fn  check_booted_microvm ( vmm :  Arc < Mutex < Vmm > > ,  mut  evmgr :  EventManager )  { 
36+     // On x86_64, the vmm should exit once its workload completes and signals the exit event. 
37+     // On aarch64, the test kernel doesn't exit, so the vmm is force-stopped. 
38+     #[ cfg( target_arch = "x86_64" ) ]  
39+     evmgr. run_with_timeout ( 500 ) . unwrap ( ) ; 
40+     #[ cfg( target_arch = "aarch64" ) ]  
41+     vmm. lock ( ) . unwrap ( ) . stop ( FcExitCode :: Ok ) ; 
42+ 
43+     assert_eq ! ( 
44+         vmm. lock( ) . unwrap( ) . shutdown_exit_code( ) , 
45+         Some ( FcExitCode :: Ok ) 
46+     ) ; 
47+ } 
48+ 
3249#[ test]  
3350fn  test_build_and_boot_microvm ( )  { 
3451    // Error case: no boot source configured. 
@@ -47,33 +64,24 @@ fn test_build_and_boot_microvm() {
4764    } 
4865
4966    // Success case. 
50-     let  ( vmm,  mut  _evmgr)  = default_vmm ( None ) ; 
67+     let  ( vmm,  evmgr)  = default_vmm ( None ) ; 
68+     check_booted_microvm ( vmm,  evmgr) ; 
5169
52-     // On x86_64, the vmm should exit once its workload completes and signals the exit event. 
53-     // On aarch64, the test kernel doesn't exit, so the vmm is force-stopped. 
54-     #[ cfg( target_arch = "x86_64" ) ]  
55-     _evmgr. run_with_timeout ( 500 ) . unwrap ( ) ; 
56-     #[ cfg( target_arch = "aarch64" ) ]  
57-     vmm. lock ( ) . unwrap ( ) . stop ( FcExitCode :: Ok ) ; 
58- 
59-     assert_eq ! ( 
60-         vmm. lock( ) . unwrap( ) . shutdown_exit_code( ) , 
61-         Some ( FcExitCode :: Ok ) 
62-     ) ; 
70+     // microVM with PCI 
71+     let  ( vmm,  evmgr)  = default_vmm_pci ( None ) ; 
72+     check_booted_microvm ( vmm,  evmgr) ; 
6373} 
6474
65- #[ test]  
66- fn  test_build_microvm ( )  { 
75+ fn  check_build_microvm ( vmm :  Arc < Mutex < Vmm > > ,  mut  evmgr :  EventManager )  { 
6776    // The built microVM should be in the `VmState::Paused` state here. 
68-     let  ( vmm,  mut  _evtmgr)  = default_vmm_no_boot ( None ) ; 
6977    assert_eq ! ( vmm. lock( ) . unwrap( ) . instance_info( ) . state,  VmState :: Paused ) ; 
7078
7179    // The microVM should be able to resume and exit successfully. 
7280    // On x86_64, the vmm should exit once its workload completes and signals the exit event. 
7381    // On aarch64, the test kernel doesn't exit, so the vmm is force-stopped. 
7482    vmm. lock ( ) . unwrap ( ) . resume_vm ( ) . unwrap ( ) ; 
7583    #[ cfg( target_arch = "x86_64" ) ]  
76-     _evtmgr . run_with_timeout ( 500 ) . unwrap ( ) ; 
84+     evmgr . run_with_timeout ( 500 ) . unwrap ( ) ; 
7785    #[ cfg( target_arch = "aarch64" ) ]  
7886    vmm. lock ( ) . unwrap ( ) . stop ( FcExitCode :: Ok ) ; 
7987    assert_eq ! ( 
@@ -83,10 +91,14 @@ fn test_build_microvm() {
8391} 
8492
8593#[ test]  
86- fn  test_pause_resume_microvm ( )  { 
87-     // Tests that pausing and resuming a microVM work as expected. 
88-     let  ( vmm,  _)  = default_vmm ( None ) ; 
94+ fn  test_build_microvm ( )  { 
95+     let  ( vmm,  evtmgr)  = default_vmm_no_boot ( None ) ; 
96+     check_build_microvm ( vmm,  evtmgr) ; 
97+     let  ( vmm,  evtmgr)  = default_vmm_pci_no_boot ( None ) ; 
98+     check_build_microvm ( vmm,  evtmgr) ; 
99+ } 
89100
101+ fn  pause_resume_microvm ( vmm :  Arc < Mutex < Vmm > > )  { 
90102    let  mut  api_controller = RuntimeApiController :: new ( VmResources :: default ( ) ,  vmm. clone ( ) ) ; 
91103
92104    // There's a race between this thread and the vcpu thread, but this thread 
@@ -100,6 +112,17 @@ fn test_pause_resume_microvm() {
100112    vmm. lock ( ) . unwrap ( ) . stop ( FcExitCode :: Ok ) ; 
101113} 
102114
115+ #[ test]  
116+ fn  test_pause_resume_microvm ( )  { 
117+     // Tests that pausing and resuming a microVM work as expected. 
118+     let  ( vmm,  _)  = default_vmm ( None ) ; 
119+ 
120+     pause_resume_microvm ( vmm) ; 
121+ 
122+     let  ( vmm,  _)  = default_vmm_pci ( None ) ; 
123+     pause_resume_microvm ( vmm) ; 
124+ } 
125+ 
103126#[ test]  
104127fn  test_dirty_bitmap_error ( )  { 
105128    // Error case: dirty tracking disabled. 
@@ -185,11 +208,11 @@ fn test_disallow_dump_cpu_config_without_pausing() {
185208    vmm. lock ( ) . unwrap ( ) . stop ( FcExitCode :: Ok ) ; 
186209} 
187210
188- fn  verify_create_snapshot ( is_diff :  bool )  -> ( TempFile ,  TempFile )  { 
211+ fn  verify_create_snapshot ( is_diff :  bool ,   pci_enabled :   bool )  -> ( TempFile ,  TempFile )  { 
189212    let  snapshot_file = TempFile :: new ( ) . unwrap ( ) ; 
190213    let  memory_file = TempFile :: new ( ) . unwrap ( ) ; 
191214
192-     let  ( vmm,  _)  = create_vmm ( Some ( NOISY_KERNEL_IMAGE ) ,  is_diff,  true ) ; 
215+     let  ( vmm,  _)  = create_vmm ( Some ( NOISY_KERNEL_IMAGE ) ,  is_diff,  true ,  pci_enabled ) ; 
193216    let  resources = VmResources  { 
194217        machine_config :  MachineConfig  { 
195218            mem_size_mib :  1 , 
@@ -296,29 +319,27 @@ fn verify_load_snapshot(snapshot_file: TempFile, memory_file: TempFile) {
296319
297320#[ test]  
298321fn  test_create_and_load_snapshot ( )  { 
299-     // Create diff snapshot. 
300-     let  ( snapshot_file,  memory_file)  = verify_create_snapshot ( true ) ; 
301-     // Create a new microVm from snapshot. This only tests code-level logic; it verifies 
302-     // that a microVM can be built with no errors from given snapshot. 
303-     // It does _not_ verify that the guest is actually restored properly. We're using 
304-     // python integration tests for that. 
305-     verify_load_snapshot ( snapshot_file,  memory_file) ; 
306- 
307-     // Create full snapshot. 
308-     let  ( snapshot_file,  memory_file)  = verify_create_snapshot ( false ) ; 
309-     // Create a new microVm from snapshot. This only tests code-level logic; it verifies 
310-     // that a microVM can be built with no errors from given snapshot. 
311-     // It does _not_ verify that the guest is actually restored properly. We're using 
312-     // python integration tests for that. 
313-     verify_load_snapshot ( snapshot_file,  memory_file) ; 
322+     for  ( diff_snap,  pci_enabled)  in  [ ( false ,  false ) ,  ( false ,  true ) ,  ( true ,  false ) ,  ( true ,  true ) ]  { 
323+         // Create snapshot. 
324+         let  ( snapshot_file,  memory_file)  = verify_create_snapshot ( diff_snap,  pci_enabled) ; 
325+         // Create a new microVm from snapshot. This only tests code-level logic; it verifies 
326+         // that a microVM can be built with no errors from given snapshot. 
327+         // It does _not_ verify that the guest is actually restored properly. We're using 
328+         // python integration tests for that. 
329+         verify_load_snapshot ( snapshot_file,  memory_file) ; 
330+     } 
314331} 
315332
316333#[ test]  
317334fn  test_snapshot_load_sanity_checks ( )  { 
318-     use  vmm:: persist:: SnapShotStateSanityCheckError ; 
319- 
320-     let  mut  microvm_state = get_microvm_state_from_snapshot ( ) ; 
335+     let  microvm_state = get_microvm_state_from_snapshot ( false ) ; 
336+     check_snapshot ( microvm_state) ; 
337+     let  microvm_state = get_microvm_state_from_snapshot ( true ) ; 
338+     check_snapshot ( microvm_state) ; 
339+ } 
321340
341+ fn  check_snapshot ( mut  microvm_state :  MicrovmState )  { 
342+     use  vmm:: persist:: SnapShotStateSanityCheckError ; 
322343    snapshot_state_sanity_check ( & microvm_state) . unwrap ( ) ; 
323344
324345    // Remove memory regions. 
@@ -331,9 +352,9 @@ fn test_snapshot_load_sanity_checks() {
331352    ) ; 
332353} 
333354
334- fn  get_microvm_state_from_snapshot ( )  -> MicrovmState  { 
355+ fn  get_microvm_state_from_snapshot ( pci_enabled :   bool )  -> MicrovmState  { 
335356    // Create a diff snapshot 
336-     let  ( snapshot_file,  _)  = verify_create_snapshot ( true ) ; 
357+     let  ( snapshot_file,  _)  = verify_create_snapshot ( true ,  pci_enabled ) ; 
337358
338359    // Deserialize the microVM state. 
339360    let  snapshot_file_metadata = snapshot_file. as_file ( ) . metadata ( ) . unwrap ( ) ; 
@@ -344,7 +365,7 @@ fn get_microvm_state_from_snapshot() -> MicrovmState {
344365} 
345366
346367fn  verify_load_snap_disallowed_after_boot_resources ( res :  VmmAction ,  res_name :  & str )  { 
347-     let  ( snapshot_file,  memory_file)  = verify_create_snapshot ( false ) ; 
368+     let  ( snapshot_file,  memory_file)  = verify_create_snapshot ( false ,   false ) ; 
348369
349370    let  mut  event_manager = EventManager :: new ( ) . unwrap ( ) ; 
350371    let  empty_seccomp_filters = get_empty_filters ( ) ; 
0 commit comments