xref: /aosp_15_r20/external/crosvm/hypervisor/tests/remove_memory.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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(&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