Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/hypervisor/tests/remove_memory.rs
5394 views
1
// Copyright 2020 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 base::MemoryMappingBuilder;
10
use base::SharedMemory;
11
use hypervisor::*;
12
use vm_memory::GuestAddress;
13
use vm_memory::GuestMemory;
14
15
#[test]
16
#[cfg(any(target_os = "android", target_os = "linux"))]
17
fn test_kvm_remove_memory() {
18
use hypervisor::kvm::*;
19
test_remove_memory(|guest_mem| {
20
let kvm = Kvm::new().expect("failed to create kvm");
21
let vm = KvmVm::new(&kvm, guest_mem, Default::default()).expect("failed to create vm");
22
(kvm, vm)
23
});
24
}
25
26
#[test]
27
#[cfg(all(windows, feature = "haxm"))]
28
fn test_haxm_remove_memory() {
29
use hypervisor::haxm::*;
30
test_remove_memory(|guest_mem| {
31
let haxm = Haxm::new().expect("failed to create haxm");
32
let vm = HaxmVm::new(&haxm, guest_mem).expect("failed to create vm");
33
(haxm, vm)
34
});
35
}
36
37
#[test]
38
#[cfg(feature = "gvm")]
39
fn test_gvm_remove_memory() {
40
use hypervisor::gvm::*;
41
test_remove_memory(|guest_mem| {
42
let gvm = Gvm::new().expect("failed to create gvm");
43
let vm = GvmVm::new(&gvm, guest_mem).expect("failed to create vm");
44
(gvm, vm)
45
});
46
}
47
48
#[test]
49
#[cfg(all(windows, feature = "whpx"))]
50
fn test_whpx_remove_memory() {
51
use hypervisor::whpx::*;
52
if !Whpx::is_enabled() {
53
return;
54
}
55
test_remove_memory(|guest_mem| {
56
let whpx = Whpx::new().expect("failed to create whpx");
57
let vm =
58
WhpxVm::new(&whpx, 1, guest_mem, CpuId::new(0), false).expect("failed to create vm");
59
(whpx, vm)
60
});
61
}
62
63
fn test_remove_memory<CreateVm, HypervisorT, VmT>(create_vm: CreateVm)
64
where
65
CreateVm: FnOnce(GuestMemory) -> (HypervisorT, VmT),
66
HypervisorT: Hypervisor,
67
VmT: VmX86_64,
68
{
69
/*
70
0x0000000000000000: A0 00 30 mov al, byte ptr [0x3000]
71
0x0000000000000003: F4 hlt
72
*/
73
let code = [0xa0, 0x00, 0x30, 0xf4];
74
let mem_size = 0x2000;
75
let load_addr = GuestAddress(0x1000);
76
77
// GuestMemory requires an initial set of memory, so we just
78
// setup some at 0x8000, it won't be used though.
79
let guest_mem =
80
GuestMemory::new(&[(GuestAddress(0x8000), 0x1000)]).expect("failed to create guest mem");
81
let mem = SharedMemory::new("test", mem_size).expect("failed to create shared memory");
82
let mmap = MemoryMappingBuilder::new(mem_size as usize)
83
.from_shared_memory(&mem)
84
.build()
85
.expect("failed to create memory mapping");
86
87
mmap.write_slice(&code[..], load_addr.offset() as usize)
88
.expect("Writing code to memory failed.");
89
90
let (_, mut vm) = create_vm(guest_mem);
91
let mut vcpu = vm.create_vcpu(0).expect("new vcpu failed");
92
let mut vcpu_sregs = vcpu.get_sregs().expect("get sregs failed");
93
vcpu_sregs.cs.base = 0;
94
vcpu_sregs.cs.selector = 0;
95
vcpu.set_sregs(&vcpu_sregs).expect("set sregs failed");
96
97
let vcpu_regs = Regs {
98
rip: load_addr.offset(),
99
rflags: 2,
100
..Default::default()
101
};
102
vcpu.set_regs(&vcpu_regs).expect("set regs failed");
103
vm.add_memory_region(
104
GuestAddress(0),
105
Box::new(
106
MemoryMappingBuilder::new(mem_size as usize)
107
.from_shared_memory(&mem)
108
.build()
109
.expect("failed to create memory mapping"),
110
),
111
false,
112
false,
113
MemCacheType::CacheCoherent,
114
)
115
.expect("failed to register memory");
116
117
// This is our memory that we will remove
118
let mem_to_remove = SharedMemory::new("test", 0x1000).expect("failed to create shared memory");
119
120
let mmap_to_remove = MemoryMappingBuilder::new(0x1000)
121
.from_shared_memory(&mem_to_remove)
122
.build()
123
.expect("failed to create memory mapping");
124
mmap_to_remove
125
.write_obj(0x55, 0)
126
.expect("failed writing data to ro memory");
127
let slot_to_remove = vm
128
.add_memory_region(
129
GuestAddress(0x3000),
130
Box::new(
131
MemoryMappingBuilder::new(0x1000)
132
.from_shared_memory(&mem_to_remove)
133
.build()
134
.expect("failed to create memory mapping"),
135
),
136
false,
137
false,
138
MemCacheType::CacheCoherent,
139
)
140
.expect("failed to register memory");
141
142
// We do our initial run of our program, it should load the value of 0x55
143
// from guest address 0x3000 into rax
144
loop {
145
match vcpu.run().expect("run failed") {
146
// Continue on external interrupt or signal
147
VcpuExit::Intr => continue,
148
VcpuExit::Hlt => break,
149
r => panic!("unexpected exit reason: {r:?}"),
150
}
151
}
152
153
let mut regs = vcpu.get_regs().expect("failed to get regs");
154
assert_eq!(regs.rax, 0x55);
155
156
// now we're going to run the same instructions again, but remove the memory first
157
regs.rax = 0;
158
regs.rip = load_addr.offset();
159
vcpu.set_regs(&regs).expect("failed to set regs");
160
// now that we have removed the memory region at 0x3000, the mov [0x3000],al instruction
161
// should produce mmio
162
vm.remove_memory_region(slot_to_remove)
163
.expect("failed to remove memory region");
164
165
loop {
166
match vcpu.run().expect("run failed") {
167
// Continue on external interrupt or signal
168
VcpuExit::Intr => continue,
169
VcpuExit::Hlt => break,
170
VcpuExit::Mmio => {
171
vcpu.handle_mmio(&mut |IoParams { address, operation }| match operation {
172
IoOperation::Read(data) => {
173
assert_eq!(address, 0x3000);
174
assert_eq!(data.len(), 1);
175
data.copy_from_slice(&[0x44]);
176
Ok(())
177
}
178
IoOperation::Write(_) => {
179
panic!("unexpected mmio write");
180
}
181
})
182
.expect("failed to set the data");
183
}
184
r => panic!("unexpected exit reason: {r:?}"),
185
}
186
}
187
188
let regs = vcpu.get_regs().expect("failed to get regs");
189
assert_eq!(regs.rax, 0x44);
190
}
191
192