xref: /aosp_15_r20/external/crosvm/hypervisor/tests/real_run_addr.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2017 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // TODO(b/237714823): Currently, only kvm is enabled for this test once LUCI can run windows.
6 #![cfg(any(target_os = "android", target_os = "linux"))]
7 #![cfg(target_arch = "x86_64")]
8 
9 use hypervisor::*;
10 use sync::Mutex;
11 use vm_memory::GuestAddress;
12 use vm_memory::GuestMemory;
13 
14 #[test]
15 #[cfg(any(target_os = "android", target_os = "linux"))]
test_kvm_real_run_addr()16 fn test_kvm_real_run_addr() {
17     use hypervisor::kvm::*;
18     test_real_run_addr(|guest_mem| {
19         let kvm = Kvm::new().expect("failed to create kvm");
20         let vm = KvmVm::new(&kvm, guest_mem, Default::default()).expect("failed to create vm");
21         (kvm, vm)
22     });
23 }
24 
25 #[test]
26 #[cfg(all(windows, feature = "haxm"))]
test_haxm_real_run_addr()27 fn test_haxm_real_run_addr() {
28     use hypervisor::haxm::*;
29     test_real_run_addr(|guest_mem| {
30         let haxm = Haxm::new().expect("failed to create haxm");
31         let vm = HaxmVm::new(&haxm, guest_mem).expect("failed to create vm");
32         (haxm, vm)
33     });
34 }
35 
36 #[test]
37 #[cfg(feature = "gvm")]
test_gvm_real_run_addr()38 fn test_gvm_real_run_addr() {
39     use hypervisor::gvm::*;
40     test_real_run_addr(|guest_mem| {
41         let gvm = Gvm::new().expect("failed to create gvm");
42         let vm = GvmVm::new(&gvm, guest_mem).expect("failed to create vm");
43         (gvm, vm)
44     });
45 }
46 
47 #[test]
48 #[cfg(all(windows, feature = "whpx"))]
test_whpx_real_run_addr()49 fn test_whpx_real_run_addr() {
50     use hypervisor::whpx::*;
51     if !Whpx::is_enabled() {
52         return;
53     }
54     test_real_run_addr(|guest_mem| {
55         let whpx = Whpx::new().expect("failed to create whpx");
56         let vm =
57             WhpxVm::new(&whpx, 1, guest_mem, CpuId::new(0), false).expect("failed to create vm");
58         (whpx, vm)
59     });
60 }
61 
test_real_run_addr<CreateVm, HypervisorT, VmT>(create_vm: CreateVm) where CreateVm: FnOnce(GuestMemory) -> (HypervisorT, VmT), HypervisorT: Hypervisor, VmT: VmX86_64,62 fn test_real_run_addr<CreateVm, HypervisorT, VmT>(create_vm: CreateVm)
63 where
64     CreateVm: FnOnce(GuestMemory) -> (HypervisorT, VmT),
65     HypervisorT: Hypervisor,
66     VmT: VmX86_64,
67 {
68     // This example based on https://lwn.net/Articles/658511/
69     let code = [
70         0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */
71         0x00, 0xd8, /* add %bl, %al */
72         0x04, b'0', /* add $'0', %al */
73         0xee, /* out %al, (%dx) */
74         0xb0, b'\n', /* mov $'\n', %al */
75         0xee,  /* out %al, (%dx) */
76         0x2e, 0xc6, 0x06, 0xf1, 0x10, 0x13, /* movb $0x13, %cs:0xf1 */
77         0xf4, /* hlt */
78     ];
79 
80     let mem_size = 0x1000;
81     let load_addr = GuestAddress(0x1000);
82     let mem = GuestMemory::new(&[(load_addr, mem_size)]).unwrap();
83 
84     let (_hyp, vm) = create_vm(mem);
85     let mut vcpu = vm.create_vcpu(0).expect("new vcpu failed");
86 
87     vm.get_memory()
88         .write_at_addr(&code, load_addr)
89         .expect("Writing code to memory failed.");
90 
91     let mut vcpu_sregs = vcpu.get_sregs().expect("get sregs failed");
92     assert_ne!(vcpu_sregs.cs.base, 0);
93     assert_ne!(vcpu_sregs.cs.selector, 0);
94     vcpu_sregs.cs.base = 0;
95     vcpu_sregs.cs.selector = 0;
96     vcpu.set_sregs(&vcpu_sregs).expect("set sregs failed");
97 
98     let vcpu_regs = Regs {
99         rip: 0x1000,
100         rax: 2,
101         rbx: 7,
102         rflags: 2,
103         ..Default::default()
104     };
105     vcpu.set_regs(&vcpu_regs).expect("set regs failed");
106 
107     let out = Mutex::new(String::new());
108     loop {
109         match vcpu.run().expect("run failed") {
110             VcpuExit::Io => {
111                 vcpu.handle_io(&mut |IoParams { address, operation }| match operation {
112                     IoOperation::Read(_) => {
113                         panic!("unexpected io in call");
114                     }
115                     IoOperation::Write(data) => {
116                         assert_eq!(address, 0x3f8);
117                         assert_eq!(data.len(), 1);
118                         out.lock().push(data[0] as char);
119                     }
120                 })
121                 .expect("failed to set the data");
122             }
123             // Continue on external interrupt or signal
124             VcpuExit::Intr => continue,
125             VcpuExit::Hlt => break,
126             r => panic!("unexpected exit reason: {:?}", r),
127         }
128     }
129 
130     assert_eq!(out.lock().as_str(), "9\n");
131     let result: u8 = vm
132         .get_memory()
133         .read_obj_from_addr(load_addr.checked_add(0xf1).unwrap())
134         .expect("Error reading the result.");
135     assert_eq!(result, 0x13);
136 }
137