Skip to content

Commit 09c33b1

Browse files
committed
vcpu: add test for Pause, Resume and Exit vcpu
Signed-off-by: Adrian Catangiu <[email protected]>
1 parent 5965a97 commit 09c33b1

File tree

2 files changed

+137
-10
lines changed

2 files changed

+137
-10
lines changed

src/vmm/src/vstate.rs

Lines changed: 136 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -871,15 +871,20 @@ enum VcpuEmulation {
871871
#[cfg(test)]
872872
mod 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
}

tests/integration_tests/build/test_coverage.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import host_tools.cargo_build as host # pylint: disable=import-error
2121

22-
COVERAGE_TARGET_PCT = 85.2
22+
COVERAGE_TARGET_PCT = 85.3
2323
COVERAGE_MAX_DELTA = 0.01
2424

2525
CARGO_KCOV_REL_PATH = os.path.join(host.CARGO_BUILD_REL_PATH, 'kcov')

0 commit comments

Comments
 (0)