xref: /aosp_15_r20/external/crosvm/hypervisor/tests/dirty_log.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2017 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 // TODO(b/237714823): Currently, only kvm is enabled for this test once LUCI can run windows.
6*bb4ee6a4SAndroid Build Coastguard Worker #![cfg(any(target_os = "android", target_os = "linux"))]
7*bb4ee6a4SAndroid Build Coastguard Worker #![cfg(target_arch = "x86_64")]
8*bb4ee6a4SAndroid Build Coastguard Worker #![cfg(any(feature = "whpx", feature = "gvm", feature = "haxm", unix))]
9*bb4ee6a4SAndroid Build Coastguard Worker 
10*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMappingBuilder;
11*bb4ee6a4SAndroid Build Coastguard Worker use base::SharedMemory;
12*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::*;
13*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
14*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
15*bb4ee6a4SAndroid Build Coastguard Worker 
16*bb4ee6a4SAndroid Build Coastguard Worker #[test]
17*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
test_kvm_dirty_log()18*bb4ee6a4SAndroid Build Coastguard Worker fn test_kvm_dirty_log() {
19*bb4ee6a4SAndroid Build Coastguard Worker     use hypervisor::kvm::*;
20*bb4ee6a4SAndroid Build Coastguard Worker     test_dirty_log(|guest_mem| {
21*bb4ee6a4SAndroid Build Coastguard Worker         let kvm = Kvm::new().expect("failed to create kvm");
22*bb4ee6a4SAndroid Build Coastguard Worker         let vm = KvmVm::new(&kvm, guest_mem, Default::default()).expect("failed to create vm");
23*bb4ee6a4SAndroid Build Coastguard Worker         (kvm, vm)
24*bb4ee6a4SAndroid Build Coastguard Worker     });
25*bb4ee6a4SAndroid Build Coastguard Worker }
26*bb4ee6a4SAndroid Build Coastguard Worker 
27*bb4ee6a4SAndroid Build Coastguard Worker #[test]
28*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(all(windows, feature = "haxm"))]
test_haxm_dirty_log_not_supported()29*bb4ee6a4SAndroid Build Coastguard Worker fn test_haxm_dirty_log_not_supported() {
30*bb4ee6a4SAndroid Build Coastguard Worker     // HAXM does not support dirty log, so we simply test that the capability
31*bb4ee6a4SAndroid Build Coastguard Worker     // returns false.
32*bb4ee6a4SAndroid Build Coastguard Worker 
33*bb4ee6a4SAndroid Build Coastguard Worker     use hypervisor::haxm::*;
34*bb4ee6a4SAndroid Build Coastguard Worker     let haxm = Haxm::new().expect("failed to create haxm");
35*bb4ee6a4SAndroid Build Coastguard Worker     let guest_mem = GuestMemory::new(&[(GuestAddress(0x20000), 0x1000)]).unwrap();
36*bb4ee6a4SAndroid Build Coastguard Worker     let vm = HaxmVm::new(&haxm, guest_mem).expect("failed to create vm");
37*bb4ee6a4SAndroid Build Coastguard Worker 
38*bb4ee6a4SAndroid Build Coastguard Worker     assert!(!vm.check_capability(VmCap::DirtyLog));
39*bb4ee6a4SAndroid Build Coastguard Worker }
40*bb4ee6a4SAndroid Build Coastguard Worker 
41*bb4ee6a4SAndroid Build Coastguard Worker #[test]
42*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gvm")]
test_gvm_dirty_log()43*bb4ee6a4SAndroid Build Coastguard Worker fn test_gvm_dirty_log() {
44*bb4ee6a4SAndroid Build Coastguard Worker     use hypervisor::gvm::*;
45*bb4ee6a4SAndroid Build Coastguard Worker     test_dirty_log(|guest_mem| {
46*bb4ee6a4SAndroid Build Coastguard Worker         let gvm = Gvm::new().expect("failed to create gvm");
47*bb4ee6a4SAndroid Build Coastguard Worker         let vm = GvmVm::new(&gvm, guest_mem).expect("failed to create vm");
48*bb4ee6a4SAndroid Build Coastguard Worker         (gvm, vm)
49*bb4ee6a4SAndroid Build Coastguard Worker     });
50*bb4ee6a4SAndroid Build Coastguard Worker }
51*bb4ee6a4SAndroid Build Coastguard Worker 
52*bb4ee6a4SAndroid Build Coastguard Worker #[test]
53*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(all(windows, feature = "whpx"))]
test_whpx_dirty_log()54*bb4ee6a4SAndroid Build Coastguard Worker fn test_whpx_dirty_log() {
55*bb4ee6a4SAndroid Build Coastguard Worker     use hypervisor::whpx::*;
56*bb4ee6a4SAndroid Build Coastguard Worker     if !Whpx::is_enabled() {
57*bb4ee6a4SAndroid Build Coastguard Worker         return;
58*bb4ee6a4SAndroid Build Coastguard Worker     }
59*bb4ee6a4SAndroid Build Coastguard Worker     test_dirty_log(|guest_mem| {
60*bb4ee6a4SAndroid Build Coastguard Worker         let whpx = Whpx::new().expect("failed to create whpx");
61*bb4ee6a4SAndroid Build Coastguard Worker         let vm =
62*bb4ee6a4SAndroid Build Coastguard Worker             WhpxVm::new(&whpx, 1, guest_mem, CpuId::new(0), false).expect("failed to create vm");
63*bb4ee6a4SAndroid Build Coastguard Worker         (whpx, vm)
64*bb4ee6a4SAndroid Build Coastguard Worker     });
65*bb4ee6a4SAndroid Build Coastguard Worker }
66*bb4ee6a4SAndroid Build Coastguard Worker 
test_dirty_log<CreateVm, HypervisorT, VmT>(create_vm: CreateVm) where CreateVm: FnOnce(GuestMemory) -> (HypervisorT, VmT), HypervisorT: Hypervisor, VmT: VmX86_64,67*bb4ee6a4SAndroid Build Coastguard Worker fn test_dirty_log<CreateVm, HypervisorT, VmT>(create_vm: CreateVm)
68*bb4ee6a4SAndroid Build Coastguard Worker where
69*bb4ee6a4SAndroid Build Coastguard Worker     CreateVm: FnOnce(GuestMemory) -> (HypervisorT, VmT),
70*bb4ee6a4SAndroid Build Coastguard Worker     HypervisorT: Hypervisor,
71*bb4ee6a4SAndroid Build Coastguard Worker     VmT: VmX86_64,
72*bb4ee6a4SAndroid Build Coastguard Worker {
73*bb4ee6a4SAndroid Build Coastguard Worker     /*
74*bb4ee6a4SAndroid Build Coastguard Worker     0000  881C mov [si],bl
75*bb4ee6a4SAndroid Build Coastguard Worker     0002  F4   hlt
76*bb4ee6a4SAndroid Build Coastguard Worker     */
77*bb4ee6a4SAndroid Build Coastguard Worker     let code = [0x88, 0x1c, 0xf4];
78*bb4ee6a4SAndroid Build Coastguard Worker     let mem_size = 0x10000;
79*bb4ee6a4SAndroid Build Coastguard Worker     let load_addr = GuestAddress(0x1000);
80*bb4ee6a4SAndroid Build Coastguard Worker     // GuestMemory requires an initial set of memory, so we just
81*bb4ee6a4SAndroid Build Coastguard Worker     // setup some at 0x20000, it won't be used though.
82*bb4ee6a4SAndroid Build Coastguard Worker     let guest_mem = GuestMemory::new(&[(GuestAddress(0x20000), 0x1000)]).unwrap();
83*bb4ee6a4SAndroid Build Coastguard Worker     let mem = SharedMemory::new("test", mem_size).expect("failed to create shared memory");
84*bb4ee6a4SAndroid Build Coastguard Worker     let mmap = MemoryMappingBuilder::new(mem_size as usize)
85*bb4ee6a4SAndroid Build Coastguard Worker         .from_shared_memory(&mem)
86*bb4ee6a4SAndroid Build Coastguard Worker         .build()
87*bb4ee6a4SAndroid Build Coastguard Worker         .expect("failed to create memory mapping");
88*bb4ee6a4SAndroid Build Coastguard Worker 
89*bb4ee6a4SAndroid Build Coastguard Worker     mmap.write_slice(&code[..], load_addr.offset() as usize)
90*bb4ee6a4SAndroid Build Coastguard Worker         .expect("Writing code to memory failed.");
91*bb4ee6a4SAndroid Build Coastguard Worker 
92*bb4ee6a4SAndroid Build Coastguard Worker     let (_hyp, mut vm) = create_vm(guest_mem);
93*bb4ee6a4SAndroid Build Coastguard Worker     let mut vcpu = vm.create_vcpu(0).expect("new vcpu failed");
94*bb4ee6a4SAndroid Build Coastguard Worker     let mut vcpu_sregs = vcpu.get_sregs().expect("get sregs failed");
95*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_sregs.cs.base = 0;
96*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_sregs.cs.selector = 0;
97*bb4ee6a4SAndroid Build Coastguard Worker     vcpu.set_sregs(&vcpu_sregs).expect("set sregs failed");
98*bb4ee6a4SAndroid Build Coastguard Worker 
99*bb4ee6a4SAndroid Build Coastguard Worker     let vcpu_regs = Regs {
100*bb4ee6a4SAndroid Build Coastguard Worker         rip: load_addr.offset(),
101*bb4ee6a4SAndroid Build Coastguard Worker         rflags: 2,
102*bb4ee6a4SAndroid Build Coastguard Worker         // Write 0x12 to the beginning of the 9th page.
103*bb4ee6a4SAndroid Build Coastguard Worker         rsi: 0x8000,
104*bb4ee6a4SAndroid Build Coastguard Worker         rbx: 0x12,
105*bb4ee6a4SAndroid Build Coastguard Worker         ..Default::default()
106*bb4ee6a4SAndroid Build Coastguard Worker     };
107*bb4ee6a4SAndroid Build Coastguard Worker     vcpu.set_regs(&vcpu_regs).expect("set regs failed");
108*bb4ee6a4SAndroid Build Coastguard Worker     let slot = vm
109*bb4ee6a4SAndroid Build Coastguard Worker         .add_memory_region(
110*bb4ee6a4SAndroid Build Coastguard Worker             GuestAddress(0),
111*bb4ee6a4SAndroid Build Coastguard Worker             Box::new(
112*bb4ee6a4SAndroid Build Coastguard Worker                 MemoryMappingBuilder::new(mem_size as usize)
113*bb4ee6a4SAndroid Build Coastguard Worker                     .from_shared_memory(&mem)
114*bb4ee6a4SAndroid Build Coastguard Worker                     .build()
115*bb4ee6a4SAndroid Build Coastguard Worker                     .expect("failed to create memory mapping"),
116*bb4ee6a4SAndroid Build Coastguard Worker             ),
117*bb4ee6a4SAndroid Build Coastguard Worker             false,
118*bb4ee6a4SAndroid Build Coastguard Worker             true,
119*bb4ee6a4SAndroid Build Coastguard Worker             MemCacheType::CacheCoherent,
120*bb4ee6a4SAndroid Build Coastguard Worker         )
121*bb4ee6a4SAndroid Build Coastguard Worker         .expect("failed to register memory");
122*bb4ee6a4SAndroid Build Coastguard Worker 
123*bb4ee6a4SAndroid Build Coastguard Worker     loop {
124*bb4ee6a4SAndroid Build Coastguard Worker         match vcpu.run().expect("run failed") {
125*bb4ee6a4SAndroid Build Coastguard Worker             // Continue on external interrupt or signal
126*bb4ee6a4SAndroid Build Coastguard Worker             VcpuExit::Intr => continue,
127*bb4ee6a4SAndroid Build Coastguard Worker             VcpuExit::Hlt => break,
128*bb4ee6a4SAndroid Build Coastguard Worker             r => panic!("unexpected exit reason: {:?}", r),
129*bb4ee6a4SAndroid Build Coastguard Worker         }
130*bb4ee6a4SAndroid Build Coastguard Worker     }
131*bb4ee6a4SAndroid Build Coastguard Worker 
132*bb4ee6a4SAndroid Build Coastguard Worker     let mut dirty_log = [0x0, 0x0];
133*bb4ee6a4SAndroid Build Coastguard Worker     vm.get_dirty_log(slot, &mut dirty_log[..])
134*bb4ee6a4SAndroid Build Coastguard Worker         .expect("failed to get dirty log");
135*bb4ee6a4SAndroid Build Coastguard Worker     // Tests the 9th page was written to.
136*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(dirty_log[1], 0x1);
137*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(
138*bb4ee6a4SAndroid Build Coastguard Worker         mmap.read_obj::<u64>(vcpu_regs.rsi as usize).unwrap(),
139*bb4ee6a4SAndroid Build Coastguard Worker         vcpu_regs.rbx
140*bb4ee6a4SAndroid Build Coastguard Worker     );
141*bb4ee6a4SAndroid Build Coastguard Worker }
142