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"))]
test_kvm_remove_memory()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"))]
test_haxm_remove_memory()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")]
test_gvm_remove_memory()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"))]
test_whpx_remove_memory()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
test_remove_memory<CreateVm, HypervisorT, VmT>(create_vm: CreateVm) where CreateVm: FnOnce(GuestMemory) -> (HypervisorT, VmT), HypervisorT: Hypervisor, VmT: VmX86_64,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(®s).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