Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/hypervisor/tests/read_only_memory.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
9
use std::sync::atomic::AtomicU16;
10
use std::sync::atomic::Ordering;
11
12
use base::MemoryMappingBuilder;
13
use base::SharedMemory;
14
use hypervisor::*;
15
use vm_memory::GuestAddress;
16
use vm_memory::GuestMemory;
17
18
#[test]
19
#[cfg(any(target_os = "android", target_os = "linux"))]
20
fn test_kvm_read_only_memory() {
21
use hypervisor::kvm::*;
22
test_read_only_memory(|guest_mem| {
23
let kvm = Kvm::new().expect("failed to create kvm");
24
let vm = KvmVm::new(&kvm, guest_mem, Default::default()).expect("failed to create vm");
25
(kvm, vm)
26
});
27
}
28
29
// TODO(b/163163457): HAXM has a bug where the mmio write for read only memory
30
// does not happen to the correct address.
31
// #[test]
32
// #[cfg(all(windows, feature = "haxm"))]
33
// fn test_haxm_read_only_memory() {
34
// use hypervisor::haxm::*;
35
// test_read_only_memory(|guest_mem| {
36
// let haxm = Haxm::new().expect("failed to create haxm");
37
// let vm = HaxmVm::new(&haxm, guest_mem).expect("failed to create vm");
38
// (haxm, vm)
39
// });
40
// }
41
42
#[test]
43
#[cfg(feature = "gvm")]
44
fn test_gvm_read_only_memory() {
45
use hypervisor::gvm::*;
46
test_read_only_memory(|guest_mem| {
47
let gvm = Gvm::new().expect("failed to create gvm");
48
let vm = GvmVm::new(&gvm, guest_mem).expect("failed to create vm");
49
(gvm, vm)
50
});
51
}
52
53
// TODO(b/163163457): whpx also fails with guest cannot be faulted
54
/*#[test]
55
#[cfg(all(windows, feature = "whpx"))]
56
fn test_whpx_read_only_memory() {
57
use hypervisor::whpx::*;
58
if !Whpx::is_enabled() { return; }
59
test_read_only_memory(|guest_mem| {
60
let whpx = Whpx::new().expect("failed to create whpx");
61
let vm = WhpxVm::new(&whpx, 1, guest_mem, CpuId::new(0), false)
62
.expect("failed to create vm");
63
(whpx, vm)
64
});
65
}*/
66
67
fn test_read_only_memory<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 268A07 mov al,[es:bx]
75
0003 0401 add al,0x1
76
0005 268807 mov [es:bx],al
77
0008 F4 hlt
78
*/
79
let code = [0x26, 0x8a, 0x07, 0x04, 0x01, 0x26, 0x88, 0x07, 0xf4];
80
let mem_size = 0x2000;
81
let load_addr = GuestAddress(0x1000);
82
83
// GuestMemory requires an initial set of memory, so we just
84
// setup some at 0x8000, it won't be used though.
85
let guest_mem =
86
GuestMemory::new(&[(GuestAddress(0x8000), 0x1000)]).expect("failed to create guest mem");
87
let mem = SharedMemory::new("test", mem_size).expect("failed to create shared memory");
88
let mmap = MemoryMappingBuilder::new(mem_size as usize)
89
.from_shared_memory(&mem)
90
.build()
91
.expect("failed to create memory mapping");
92
93
mmap.write_slice(&code[..], load_addr.offset() as usize)
94
.expect("Writing code to memory failed.");
95
96
let (_, mut vm) = create_vm(guest_mem);
97
let mut vcpu = vm.create_vcpu(0).expect("new vcpu failed");
98
let mut vcpu_sregs = vcpu.get_sregs().expect("get sregs failed");
99
vcpu_sregs.cs.base = 0;
100
vcpu_sregs.cs.selector = 0;
101
vcpu_sregs.cs.s = 1;
102
vcpu_sregs.cs.type_ = 0b1011;
103
vcpu_sregs.es.base = 0x3000;
104
vcpu_sregs.es.selector = 0;
105
vcpu_sregs.es.s = 1;
106
vcpu_sregs.es.type_ = 0b1011;
107
108
vcpu.set_sregs(&vcpu_sregs).expect("set sregs failed");
109
110
let vcpu_regs = Regs {
111
rip: load_addr.offset(),
112
rflags: 2,
113
rax: 0,
114
rbx: 0,
115
..Default::default()
116
};
117
vcpu.set_regs(&vcpu_regs).expect("set regs failed");
118
vm.add_memory_region(
119
GuestAddress(0),
120
Box::new(
121
MemoryMappingBuilder::new(mem_size as usize)
122
.from_shared_memory(&mem)
123
.build()
124
.expect("failed to create memory mapping"),
125
),
126
false,
127
false,
128
MemCacheType::CacheCoherent,
129
)
130
.expect("failed to register memory");
131
132
// Give some read only memory for the test code to read from and force a vcpu exit when it reads
133
// from it.
134
let mem_ro = SharedMemory::new("test", 0x1000).expect("failed to create shared memory");
135
136
let mmap_ro = MemoryMappingBuilder::new(0x1000)
137
.from_shared_memory(&mem_ro)
138
.build()
139
.expect("failed to create memory mapping");
140
mmap_ro
141
.write_obj(0x66, 0)
142
.expect("failed writing data to ro memory");
143
vm.add_memory_region(
144
GuestAddress(vcpu_sregs.es.base),
145
Box::new(
146
MemoryMappingBuilder::new(0x1000)
147
.from_shared_memory(&mem_ro)
148
.build()
149
.expect("failed to create memory mapping"),
150
),
151
true,
152
false,
153
MemCacheType::CacheCoherent,
154
)
155
.expect("failed to register memory");
156
157
// Ensure we get exactly 1 exit from attempting to write to read only memory.
158
let exits = AtomicU16::new(0);
159
160
loop {
161
match vcpu.run().expect("run failed") {
162
// Continue on external interrupt or signal
163
VcpuExit::Intr => continue,
164
VcpuExit::Hlt => break,
165
VcpuExit::Mmio => {
166
vcpu.handle_mmio(&mut |IoParams { address, operation }| match operation {
167
IoOperation::Read(_) => {
168
panic!("unexpected mmio read call");
169
}
170
IoOperation::Write(data) => {
171
assert_eq!(data.len(), 1);
172
assert_eq!(address, vcpu_sregs.es.base);
173
assert_eq!(data[0], 0x67);
174
exits.fetch_add(1, Ordering::SeqCst);
175
Ok(())
176
}
177
})
178
.expect("failed to set the data");
179
}
180
r => panic!("unexpected exit reason: {r:?}"),
181
}
182
}
183
184
// Check that exactly 1 attempt to write to read only memory was made, and that the memory is
185
// unchanged after that attempt.
186
assert_eq!(exits.load(Ordering::SeqCst), 1);
187
assert_eq!(
188
mmap_ro
189
.read_obj::<u8>(0)
190
.expect("failed to read data from ro memory"),
191
0x66
192
);
193
194
let vcpu_regs = vcpu.get_regs().expect("failed to get regs");
195
assert_eq!(vcpu_regs.rax, 0x67);
196
}
197
198