@@ -871,15 +871,20 @@ enum VcpuEmulation {
871871#[ cfg( test) ]
872872mod tests {
873873 use std:: fs:: File ;
874- use std:: sync:: { Arc , Barrier } ;
874+ use std:: path:: PathBuf ;
875+ use std:: sync:: { mpsc, Arc , Barrier } ;
876+ use std:: time:: Duration ;
875877
876878 use super :: super :: devices;
877879 use super :: * ;
878880
881+ use kernel:: cmdline as kernel_cmdline;
882+ use kernel:: loader as kernel_loader;
883+
879884 // Auxiliary function being used throughout the tests.
880- fn setup_vcpu ( ) -> ( Vm , Vcpu ) {
885+ fn setup_vcpu ( mem_size : usize ) -> ( Vm , Vcpu ) {
881886 let kvm = KvmContext :: new ( ) . unwrap ( ) ;
882- let gm = GuestMemory :: new ( & [ ( GuestAddress ( 0 ) , 0x10000 ) ] ) . unwrap ( ) ;
887+ let gm = GuestMemory :: new ( & [ ( GuestAddress ( 0 ) , mem_size ) ] ) . unwrap ( ) ;
883888 let mut vm = Vm :: new ( kvm. fd ( ) ) . expect ( "Cannot create new vm" ) ;
884889 assert ! ( vm. memory_init( gm, & kvm) . is_ok( ) ) ;
885890
@@ -908,7 +913,7 @@ mod tests {
908913
909914 #[ test]
910915 fn test_set_mmio_bus ( ) {
911- let ( _, mut vcpu) = setup_vcpu ( ) ;
916+ let ( _, mut vcpu) = setup_vcpu ( 0x1000 ) ;
912917 assert ! ( vcpu. mmio_bus. is_none( ) ) ;
913918 vcpu. set_mmio_bus ( devices:: Bus :: new ( ) ) ;
914919 assert ! ( vcpu. mmio_bus. is_some( ) ) ;
@@ -985,7 +990,7 @@ mod tests {
985990 #[ cfg( target_arch = "x86_64" ) ]
986991 #[ test]
987992 fn test_configure_vcpu ( ) {
988- let ( vm, mut vcpu) = setup_vcpu ( ) ;
993+ let ( vm, mut vcpu) = setup_vcpu ( 0x10000 ) ;
989994
990995 let vm_config = VmConfig :: default ( ) ;
991996 let vm_mem = vm. memory ( ) . unwrap ( ) ;
@@ -1035,7 +1040,7 @@ mod tests {
10351040 #[ test]
10361041 #[ should_panic]
10371042 fn test_vcpu_run_failed ( ) {
1038- let ( _, mut vcpu) = setup_vcpu ( ) ;
1043+ let ( _, mut vcpu) = setup_vcpu ( 0x1000 ) ;
10391044 // Setting an invalid seccomp level should panic.
10401045 vcpu. run ( seccomp:: SECCOMP_LEVEL_ADVANCED + 10 ) ;
10411046 }
@@ -1060,7 +1065,7 @@ mod tests {
10601065
10611066 #[ test]
10621067 fn test_vcpu_tls ( ) {
1063- let ( _, mut vcpu) = setup_vcpu ( ) ;
1068+ let ( _, mut vcpu) = setup_vcpu ( 0x1000 ) ;
10641069
10651070 // Running on the TLS vcpu should fail before we actually initialize it.
10661071 unsafe {
@@ -1091,7 +1096,7 @@ mod tests {
10911096
10921097 #[ test]
10931098 fn test_invalid_tls ( ) {
1094- let ( _, mut vcpu) = setup_vcpu ( ) ;
1099+ let ( _, mut vcpu) = setup_vcpu ( 0x1000 ) ;
10951100 // Initialize vcpu TLS.
10961101 vcpu. init_thread_local_data ( ) . unwrap ( ) ;
10971102 // Trying to initialize non-empty TLS should error.
@@ -1101,7 +1106,7 @@ mod tests {
11011106 #[ test]
11021107 fn test_vcpu_kick ( ) {
11031108 Vcpu :: register_kick_signal_handler ( ) ;
1104- let ( vm, mut vcpu) = setup_vcpu ( ) ;
1109+ let ( vm, mut vcpu) = setup_vcpu ( 0x1000 ) ;
11051110
11061111 let kvm_run =
11071112 KvmRunWrapper :: mmap_from_fd ( & vcpu. fd , vm. fd . run_size ( ) ) . expect ( "cannot mmap kvm-run" ) ;
@@ -1138,4 +1143,126 @@ mod tests {
11381143 // Verify that the Vcpu saw its kvm immediate-exit as set.
11391144 assert ! ( success. load( Ordering :: Acquire ) ) ;
11401145 }
1146+
1147+ #[ cfg( target_arch = "x86_64" ) ]
1148+ fn load_good_kernel ( vm : & Vm ) -> GuestAddress {
1149+ let path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) ;
1150+ let parent = path. parent ( ) . unwrap ( ) ;
1151+
1152+ let kernel_path: PathBuf = [ parent. to_str ( ) . unwrap ( ) , "kernel/src/loader/test_elf.bin" ]
1153+ . iter ( )
1154+ . collect ( ) ;
1155+
1156+ let vm_memory = vm. memory ( ) . expect ( "vm memory not initialized" ) ;
1157+
1158+ let mut kernel_file = File :: open ( kernel_path) . expect ( "Cannot open kernel file" ) ;
1159+ let mut cmdline = kernel_cmdline:: Cmdline :: new ( arch:: CMDLINE_MAX_SIZE ) ;
1160+ assert ! ( cmdline
1161+ . insert_str( super :: super :: DEFAULT_KERNEL_CMDLINE )
1162+ . is_ok( ) ) ;
1163+ let cmdline_addr = GuestAddress ( arch:: x86_64:: layout:: CMDLINE_START ) ;
1164+
1165+ let entry_addr = kernel_loader:: load_kernel (
1166+ vm_memory,
1167+ & mut kernel_file,
1168+ arch:: x86_64:: layout:: HIMEM_START ,
1169+ )
1170+ . expect ( "failed to load kernel" ) ;
1171+
1172+ kernel_loader:: load_cmdline (
1173+ vm_memory,
1174+ cmdline_addr,
1175+ & cmdline. as_cstring ( ) . expect ( "failed to convert to cstring" ) ,
1176+ )
1177+ . expect ( "failed to load cmdline" ) ;
1178+
1179+ entry_addr
1180+ }
1181+
1182+ // Sends an event to a vcpu and expects a particular response.
1183+ fn queue_event_expect_response ( handle : & VcpuHandle , event : VcpuEvent , response : VcpuResponse ) {
1184+ handle
1185+ . send_event ( event)
1186+ . expect ( "failed to send event to vcpu" ) ;
1187+ assert_eq ! (
1188+ handle
1189+ . response_receiver( )
1190+ . recv_timeout( Duration :: from_millis( 100 ) )
1191+ . expect( "did not receive event response from vcpu" ) ,
1192+ response
1193+ ) ;
1194+ }
1195+
1196+ // Sends an event to a vcpu and expects no response.
1197+ fn queue_event_expect_timeout ( handle : & VcpuHandle , event : VcpuEvent ) {
1198+ handle
1199+ . send_event ( event)
1200+ . expect ( "failed to send event to vcpu" ) ;
1201+ assert_eq ! (
1202+ handle
1203+ . response_receiver( )
1204+ . recv_timeout( Duration :: from_millis( 100 ) ) ,
1205+ Err ( mpsc:: RecvTimeoutError :: Timeout )
1206+ ) ;
1207+ }
1208+
1209+ #[ cfg( target_arch = "x86_64" ) ]
1210+ #[ test]
1211+ fn vcpu_pause_resume ( ) {
1212+ Vcpu :: register_kick_signal_handler ( ) ;
1213+ // Need enough mem to boot linux.
1214+ let mem_size = 64 << 20 ;
1215+ let ( vm, mut vcpu) = setup_vcpu ( mem_size) ;
1216+
1217+ let vcpu_exit_evt = vcpu. exit_evt . try_clone ( ) . unwrap ( ) ;
1218+
1219+ // Needs a kernel since we'll actually run this vcpu.
1220+ let entry_addr = load_good_kernel ( & vm) ;
1221+
1222+ let vm_config = VmConfig :: default ( ) ;
1223+ let vm_mem = vm. memory ( ) . unwrap ( ) ;
1224+ vcpu. configure_x86_64 ( & vm_config, vm_mem, entry_addr)
1225+ . expect ( "failed to configure vcpu" ) ;
1226+
1227+ let seccomp_level = 0 ;
1228+ let vcpu_handle = vcpu
1229+ . start_threaded ( seccomp_level)
1230+ . expect ( "failed to start vcpu" ) ;
1231+
1232+ // Queue a Resume event, expect a response.
1233+ queue_event_expect_response ( & vcpu_handle, VcpuEvent :: Resume , VcpuResponse :: Resumed ) ;
1234+
1235+ // Queue a Pause event, expect a response.
1236+ queue_event_expect_response ( & vcpu_handle, VcpuEvent :: Pause , VcpuResponse :: Paused ) ;
1237+
1238+ // Validate vcpu handled the EINTR gracefully and didn't exit.
1239+ let err = vcpu_exit_evt. read ( ) . unwrap_err ( ) ;
1240+ assert_eq ! ( err. raw_os_error( ) . unwrap( ) , libc:: EAGAIN ) ;
1241+
1242+ // Queue another Pause event, expect no answer.
1243+ queue_event_expect_timeout ( & vcpu_handle, VcpuEvent :: Pause ) ;
1244+
1245+ // Queue a Resume event, expect a response.
1246+ queue_event_expect_response ( & vcpu_handle, VcpuEvent :: Resume , VcpuResponse :: Resumed ) ;
1247+
1248+ // Queue another Resume event, expect a response.
1249+ queue_event_expect_response ( & vcpu_handle, VcpuEvent :: Resume , VcpuResponse :: Resumed ) ;
1250+
1251+ // Queue another Pause event, expect a response.
1252+ queue_event_expect_response ( & vcpu_handle, VcpuEvent :: Pause , VcpuResponse :: Paused ) ;
1253+
1254+ // Queue a Resume event, expect a response.
1255+ queue_event_expect_response ( & vcpu_handle, VcpuEvent :: Resume , VcpuResponse :: Resumed ) ;
1256+
1257+ // Stop it by sending exit.
1258+ assert ! ( vcpu_handle. send_event( VcpuEvent :: Exit ) . is_ok( ) ) ;
1259+
1260+ // Validate vCPU thread ends execution.
1261+ vcpu_handle
1262+ . join_vcpu_thread ( )
1263+ . expect ( "failed to join thread" ) ;
1264+
1265+ // Validate that the vCPU signaled its exit.
1266+ assert_eq ! ( vcpu_exit_evt. read( ) . unwrap( ) , 1 ) ;
1267+ }
11411268}
0 commit comments