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