1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2020 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
6*bb4ee6a4SAndroid Build Coastguard Worker
7*bb4ee6a4SAndroid Build Coastguard Worker use fixture::vm::Config;
8*bb4ee6a4SAndroid Build Coastguard Worker use fixture::vm::TestVm;
9*bb4ee6a4SAndroid Build Coastguard Worker
10*bb4ee6a4SAndroid Build Coastguard Worker #[test]
boot_test_vm() -> anyhow::Result<()>11*bb4ee6a4SAndroid Build Coastguard Worker fn boot_test_vm() -> anyhow::Result<()> {
12*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(Config::new()).unwrap();
13*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(vm.exec_in_guest("echo 42")?.stdout.trim(), "42");
14*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
15*bb4ee6a4SAndroid Build Coastguard Worker }
16*bb4ee6a4SAndroid Build Coastguard Worker
17*bb4ee6a4SAndroid Build Coastguard Worker #[test]
boot_custom_vm_kernel_initrd() -> anyhow::Result<()>18*bb4ee6a4SAndroid Build Coastguard Worker fn boot_custom_vm_kernel_initrd() -> anyhow::Result<()> {
19*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config::new()
20*bb4ee6a4SAndroid Build Coastguard Worker .with_kernel("https://storage.googleapis.com/crosvm/integration_tests/benchmarks/custom-guest-bzimage-x86_64-r0001")
21*bb4ee6a4SAndroid Build Coastguard Worker .with_initrd("https://storage.googleapis.com/crosvm/integration_tests/benchmarks/custom-initramfs.cpio.gz-r0005")
22*bb4ee6a4SAndroid Build Coastguard Worker // Use a non-sense file as rootfs to prove delegate correctly function in initrd
23*bb4ee6a4SAndroid Build Coastguard Worker .with_rootfs("https://storage.googleapis.com/crosvm/integration_tests/guest-bzimage-aarch64-r0007")
24*bb4ee6a4SAndroid Build Coastguard Worker .with_stdout_hardware("serial").extra_args(vec!["--mem".to_owned(), "512".to_owned()]);
25*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(cfg).unwrap();
26*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
27*bb4ee6a4SAndroid Build Coastguard Worker vm.exec_in_guest_async("echo 42")?
28*bb4ee6a4SAndroid Build Coastguard Worker .with_timeout(Duration::from_secs(500))
29*bb4ee6a4SAndroid Build Coastguard Worker .wait_ok(&mut vm)?
30*bb4ee6a4SAndroid Build Coastguard Worker .stdout
31*bb4ee6a4SAndroid Build Coastguard Worker .trim(),
32*bb4ee6a4SAndroid Build Coastguard Worker "42"
33*bb4ee6a4SAndroid Build Coastguard Worker );
34*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
35*bb4ee6a4SAndroid Build Coastguard Worker }
36*bb4ee6a4SAndroid Build Coastguard Worker
37*bb4ee6a4SAndroid Build Coastguard Worker #[test]
boot_test_vm_uring() -> anyhow::Result<()>38*bb4ee6a4SAndroid Build Coastguard Worker fn boot_test_vm_uring() -> anyhow::Result<()> {
39*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(
40*bb4ee6a4SAndroid Build Coastguard Worker Config::new().extra_args(vec!["--async-executor".to_string(), "uring".to_string()]),
41*bb4ee6a4SAndroid Build Coastguard Worker )
42*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
43*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(vm.exec_in_guest("echo 42")?.stdout.trim(), "42");
44*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
45*bb4ee6a4SAndroid Build Coastguard Worker }
46*bb4ee6a4SAndroid Build Coastguard Worker
47*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
48*bb4ee6a4SAndroid Build Coastguard Worker #[test]
boot_test_vm_odirect()49*bb4ee6a4SAndroid Build Coastguard Worker fn boot_test_vm_odirect() {
50*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(Config::new().o_direct()).unwrap();
51*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
52*bb4ee6a4SAndroid Build Coastguard Worker }
53*bb4ee6a4SAndroid Build Coastguard Worker
54*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
55*bb4ee6a4SAndroid Build Coastguard Worker #[test]
boot_test_vm_config_file()56*bb4ee6a4SAndroid Build Coastguard Worker fn boot_test_vm_config_file() {
57*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new_with_config_file(Config::new()).unwrap();
58*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
59*bb4ee6a4SAndroid Build Coastguard Worker }
60*bb4ee6a4SAndroid Build Coastguard Worker
61*bb4ee6a4SAndroid Build Coastguard Worker /*
62*bb4ee6a4SAndroid Build Coastguard Worker * VCPU-level suspend/resume tests (which does NOT suspend the devices)
63*bb4ee6a4SAndroid Build Coastguard Worker */
64*bb4ee6a4SAndroid Build Coastguard Worker
65*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
66*bb4ee6a4SAndroid Build Coastguard Worker #[test]
vcpu_suspend_resume_succeeds()67*bb4ee6a4SAndroid Build Coastguard Worker fn vcpu_suspend_resume_succeeds() {
68*bb4ee6a4SAndroid Build Coastguard Worker // There is no easy way for us to check if the VM is actually suspended. But at
69*bb4ee6a4SAndroid Build Coastguard Worker // least exercise the code-path.
70*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(Config::new()).unwrap();
71*bb4ee6a4SAndroid Build Coastguard Worker vm.suspend().unwrap();
72*bb4ee6a4SAndroid Build Coastguard Worker vm.resume().unwrap();
73*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
74*bb4ee6a4SAndroid Build Coastguard Worker }
75*bb4ee6a4SAndroid Build Coastguard Worker
76*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
77*bb4ee6a4SAndroid Build Coastguard Worker #[test]
vcpu_suspend_resume_succeeds_with_pvclock()78*bb4ee6a4SAndroid Build Coastguard Worker fn vcpu_suspend_resume_succeeds_with_pvclock() {
79*bb4ee6a4SAndroid Build Coastguard Worker // There is no easy way for us to check if the VM is actually suspended. But at
80*bb4ee6a4SAndroid Build Coastguard Worker // least exercise the code-path.
81*bb4ee6a4SAndroid Build Coastguard Worker let mut config = Config::new();
82*bb4ee6a4SAndroid Build Coastguard Worker config = config.extra_args(vec!["--pvclock".to_string()]);
83*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(config).unwrap();
84*bb4ee6a4SAndroid Build Coastguard Worker vm.suspend().unwrap();
85*bb4ee6a4SAndroid Build Coastguard Worker vm.resume().unwrap();
86*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
87*bb4ee6a4SAndroid Build Coastguard Worker }
88*bb4ee6a4SAndroid Build Coastguard Worker
89*bb4ee6a4SAndroid Build Coastguard Worker /*
90*bb4ee6a4SAndroid Build Coastguard Worker * Full suspend/resume tests (which suspend the devices and vcpus)
91*bb4ee6a4SAndroid Build Coastguard Worker */
92*bb4ee6a4SAndroid Build Coastguard Worker
93*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
94*bb4ee6a4SAndroid Build Coastguard Worker #[test]
full_suspend_resume_test_suspend_resume_full()95*bb4ee6a4SAndroid Build Coastguard Worker fn full_suspend_resume_test_suspend_resume_full() {
96*bb4ee6a4SAndroid Build Coastguard Worker // There is no easy way for us to check if the VM is actually suspended. But at
97*bb4ee6a4SAndroid Build Coastguard Worker // least exercise the code-path.
98*bb4ee6a4SAndroid Build Coastguard Worker let mut config = Config::new();
99*bb4ee6a4SAndroid Build Coastguard Worker config = config.with_stdout_hardware("legacy-virtio-console");
100*bb4ee6a4SAndroid Build Coastguard Worker // Why this test is called "full"? Can anyone explain...?
101*bb4ee6a4SAndroid Build Coastguard Worker config = config.extra_args(vec![
102*bb4ee6a4SAndroid Build Coastguard Worker "--no-usb".to_string(),
103*bb4ee6a4SAndroid Build Coastguard Worker "--no-balloon".to_string(),
104*bb4ee6a4SAndroid Build Coastguard Worker "--no-rng".to_string(),
105*bb4ee6a4SAndroid Build Coastguard Worker ]);
106*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(config).unwrap();
107*bb4ee6a4SAndroid Build Coastguard Worker vm.suspend_full().unwrap();
108*bb4ee6a4SAndroid Build Coastguard Worker vm.resume_full().unwrap();
109*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
110*bb4ee6a4SAndroid Build Coastguard Worker }
111*bb4ee6a4SAndroid Build Coastguard Worker
112*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
113*bb4ee6a4SAndroid Build Coastguard Worker #[test]
full_suspend_resume_with_pvclock()114*bb4ee6a4SAndroid Build Coastguard Worker fn full_suspend_resume_with_pvclock() {
115*bb4ee6a4SAndroid Build Coastguard Worker // There is no easy way for us to check if the VM is actually suspended. But at
116*bb4ee6a4SAndroid Build Coastguard Worker // least exercise the code-path.
117*bb4ee6a4SAndroid Build Coastguard Worker let mut config = Config::new();
118*bb4ee6a4SAndroid Build Coastguard Worker config = config.with_stdout_hardware("legacy-virtio-console");
119*bb4ee6a4SAndroid Build Coastguard Worker config = config.extra_args(vec![
120*bb4ee6a4SAndroid Build Coastguard Worker "--no-usb".to_string(),
121*bb4ee6a4SAndroid Build Coastguard Worker "--no-balloon".to_string(),
122*bb4ee6a4SAndroid Build Coastguard Worker "--no-rng".to_string(),
123*bb4ee6a4SAndroid Build Coastguard Worker "--pvclock".to_string(),
124*bb4ee6a4SAndroid Build Coastguard Worker ]);
125*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(config).unwrap();
126*bb4ee6a4SAndroid Build Coastguard Worker vm.suspend_full().unwrap();
127*bb4ee6a4SAndroid Build Coastguard Worker vm.resume_full().unwrap();
128*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
129*bb4ee6a4SAndroid Build Coastguard Worker }
130*bb4ee6a4SAndroid Build Coastguard Worker
131*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
132*bb4ee6a4SAndroid Build Coastguard Worker #[test]
vcpu_suspend_resume_with_pvclock_adjusts_guest_clocks()133*bb4ee6a4SAndroid Build Coastguard Worker fn vcpu_suspend_resume_with_pvclock_adjusts_guest_clocks() {
134*bb4ee6a4SAndroid Build Coastguard Worker use readclock::ClockValues;
135*bb4ee6a4SAndroid Build Coastguard Worker
136*bb4ee6a4SAndroid Build Coastguard Worker // SUSPEND_DURATION defines how long the VM should be suspended
137*bb4ee6a4SAndroid Build Coastguard Worker const SUSPEND_DURATION: Duration = Duration::from_secs(2);
138*bb4ee6a4SAndroid Build Coastguard Worker const ALLOWANCE: Duration = Duration::from_secs(1);
139*bb4ee6a4SAndroid Build Coastguard Worker
140*bb4ee6a4SAndroid Build Coastguard Worker // Launch a VM with pvclock option
141*bb4ee6a4SAndroid Build Coastguard Worker let mut config = Config::new();
142*bb4ee6a4SAndroid Build Coastguard Worker config = config.with_stdout_hardware("legacy-virtio-console");
143*bb4ee6a4SAndroid Build Coastguard Worker config = config.extra_args(vec![
144*bb4ee6a4SAndroid Build Coastguard Worker "--no-usb".to_string(),
145*bb4ee6a4SAndroid Build Coastguard Worker "--no-balloon".to_string(),
146*bb4ee6a4SAndroid Build Coastguard Worker "--no-rng".to_string(),
147*bb4ee6a4SAndroid Build Coastguard Worker "--pvclock".to_string(),
148*bb4ee6a4SAndroid Build Coastguard Worker ]);
149*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(config).unwrap();
150*bb4ee6a4SAndroid Build Coastguard Worker
151*bb4ee6a4SAndroid Build Coastguard Worker // Mount the proc fs
152*bb4ee6a4SAndroid Build Coastguard Worker vm.exec_in_guest("mount proc /proc -t proc").unwrap();
153*bb4ee6a4SAndroid Build Coastguard Worker // Ensure that the kernel has virtio-pvclock
154*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
155*bb4ee6a4SAndroid Build Coastguard Worker vm.exec_in_guest("cat /proc/config.gz | gunzip | grep '^CONFIG_VIRTIO_PVCLOCK'")
156*bb4ee6a4SAndroid Build Coastguard Worker .unwrap()
157*bb4ee6a4SAndroid Build Coastguard Worker .stdout
158*bb4ee6a4SAndroid Build Coastguard Worker .trim(),
159*bb4ee6a4SAndroid Build Coastguard Worker "CONFIG_VIRTIO_PVCLOCK=y"
160*bb4ee6a4SAndroid Build Coastguard Worker );
161*bb4ee6a4SAndroid Build Coastguard Worker
162*bb4ee6a4SAndroid Build Coastguard Worker let guest_clocks_before = vm.guest_clock_values().unwrap();
163*bb4ee6a4SAndroid Build Coastguard Worker let host_clocks_before = ClockValues::now();
164*bb4ee6a4SAndroid Build Coastguard Worker vm.suspend().unwrap();
165*bb4ee6a4SAndroid Build Coastguard Worker println!("Sleeping {SUSPEND_DURATION:?}...");
166*bb4ee6a4SAndroid Build Coastguard Worker std::thread::sleep(SUSPEND_DURATION);
167*bb4ee6a4SAndroid Build Coastguard Worker vm.resume().unwrap();
168*bb4ee6a4SAndroid Build Coastguard Worker // Sleep a bit, to give the guest a chance to move the CLOCK_BOOTTIME value forward.
169*bb4ee6a4SAndroid Build Coastguard Worker std::thread::sleep(SUSPEND_DURATION);
170*bb4ee6a4SAndroid Build Coastguard Worker let guest_clocks_after = vm.guest_clock_values().unwrap();
171*bb4ee6a4SAndroid Build Coastguard Worker let host_clocks_after = ClockValues::now();
172*bb4ee6a4SAndroid Build Coastguard Worker // Calculating in f64 since the result may be negative
173*bb4ee6a4SAndroid Build Coastguard Worker let guest_mono_diff = guest_clocks_after.clock_monotonic().as_secs_f64()
174*bb4ee6a4SAndroid Build Coastguard Worker - guest_clocks_before.clock_monotonic().as_secs_f64();
175*bb4ee6a4SAndroid Build Coastguard Worker let guest_boot_diff = guest_clocks_after.clock_boottime().as_secs_f64()
176*bb4ee6a4SAndroid Build Coastguard Worker - guest_clocks_before.clock_boottime().as_secs_f64();
177*bb4ee6a4SAndroid Build Coastguard Worker let host_boot_diff = host_clocks_after.clock_boottime().as_secs_f64()
178*bb4ee6a4SAndroid Build Coastguard Worker - host_clocks_before.clock_boottime().as_secs_f64();
179*bb4ee6a4SAndroid Build Coastguard Worker
180*bb4ee6a4SAndroid Build Coastguard Worker assert!(host_boot_diff > SUSPEND_DURATION.as_secs_f64());
181*bb4ee6a4SAndroid Build Coastguard Worker // Although the BOOTTIME and MONOTONIC behavior varies in general for some real-world factors
182*bb4ee6a4SAndroid Build Coastguard Worker // like the implementation of the kernel, the virtualization platforms and hardware issues,
183*bb4ee6a4SAndroid Build Coastguard Worker // when virtio-pvclock is in use, crosvm does its best effort to maintain the following
184*bb4ee6a4SAndroid Build Coastguard Worker // invariants to make the guest's userland peaceful:
185*bb4ee6a4SAndroid Build Coastguard Worker
186*bb4ee6a4SAndroid Build Coastguard Worker // Invariants 1: Guest's MONOTONIC behaves as if they are stopped during the VM is suspended in
187*bb4ee6a4SAndroid Build Coastguard Worker // terms of crosvm's VM instance running state. In other words, the guest's monotonic
188*bb4ee6a4SAndroid Build Coastguard Worker // difference is smaller than the "real" time experienced by the host by SUSPEND_DURATION.
189*bb4ee6a4SAndroid Build Coastguard Worker let monotonic_error = guest_mono_diff + SUSPEND_DURATION.as_secs_f64() - host_boot_diff;
190*bb4ee6a4SAndroid Build Coastguard Worker assert!(monotonic_error < ALLOWANCE.as_secs_f64());
191*bb4ee6a4SAndroid Build Coastguard Worker
192*bb4ee6a4SAndroid Build Coastguard Worker // Invariants 2: Subtracting Guest's MONOTONIC from the Guest's BOOTTIME should be
193*bb4ee6a4SAndroid Build Coastguard Worker // equal to the total duration that the VM was in the "suspended" state as noted
194*bb4ee6a4SAndroid Build Coastguard Worker // in the Invariants 1.
195*bb4ee6a4SAndroid Build Coastguard Worker let guest_suspend_duration = guest_boot_diff - guest_mono_diff;
196*bb4ee6a4SAndroid Build Coastguard Worker let boottime_error = (guest_suspend_duration - SUSPEND_DURATION.as_secs_f64()).abs();
197*bb4ee6a4SAndroid Build Coastguard Worker assert!(boottime_error < ALLOWANCE.as_secs_f64());
198*bb4ee6a4SAndroid Build Coastguard Worker }
199*bb4ee6a4SAndroid Build Coastguard Worker
200*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
201*bb4ee6a4SAndroid Build Coastguard Worker #[test]
boot_test_vm_disable_sandbox()202*bb4ee6a4SAndroid Build Coastguard Worker fn boot_test_vm_disable_sandbox() {
203*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(Config::new().disable_sandbox()).unwrap();
204*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
205*bb4ee6a4SAndroid Build Coastguard Worker }
206*bb4ee6a4SAndroid Build Coastguard Worker
207*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
208*bb4ee6a4SAndroid Build Coastguard Worker #[test]
boot_test_vm_disable_sandbox_odirect()209*bb4ee6a4SAndroid Build Coastguard Worker fn boot_test_vm_disable_sandbox_odirect() {
210*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(Config::new().disable_sandbox().o_direct()).unwrap();
211*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
212*bb4ee6a4SAndroid Build Coastguard Worker }
213*bb4ee6a4SAndroid Build Coastguard Worker
214*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
215*bb4ee6a4SAndroid Build Coastguard Worker #[test]
boot_test_vm_disable_sandbox_config_file()216*bb4ee6a4SAndroid Build Coastguard Worker fn boot_test_vm_disable_sandbox_config_file() {
217*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new_with_config_file(Config::new().disable_sandbox()).unwrap();
218*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
219*bb4ee6a4SAndroid Build Coastguard Worker }
220*bb4ee6a4SAndroid Build Coastguard Worker
221*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
222*bb4ee6a4SAndroid Build Coastguard Worker #[test]
boot_test_disable_sandbox_suspend_resume()223*bb4ee6a4SAndroid Build Coastguard Worker fn boot_test_disable_sandbox_suspend_resume() {
224*bb4ee6a4SAndroid Build Coastguard Worker // There is no easy way for us to check if the VM is actually suspended. But at
225*bb4ee6a4SAndroid Build Coastguard Worker // least exercise the code-path.
226*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(Config::new().disable_sandbox()).unwrap();
227*bb4ee6a4SAndroid Build Coastguard Worker vm.suspend().unwrap();
228*bb4ee6a4SAndroid Build Coastguard Worker vm.resume().unwrap();
229*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
230*bb4ee6a4SAndroid Build Coastguard Worker }
231