xref: /aosp_15_r20/external/crosvm/hypervisor/src/whpx/vm.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use core::ffi::c_void;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::cmp::Reverse;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BinaryHeap;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryInto;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
11*bb4ee6a4SAndroid Build Coastguard Worker 
12*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
13*bb4ee6a4SAndroid Build Coastguard Worker use base::info;
14*bb4ee6a4SAndroid Build Coastguard Worker use base::pagesize;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
16*bb4ee6a4SAndroid Build Coastguard Worker use base::Error;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::MappedRegion;
19*bb4ee6a4SAndroid Build Coastguard Worker use base::MmapError;
20*bb4ee6a4SAndroid Build Coastguard Worker use base::Protection;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::Result;
23*bb4ee6a4SAndroid Build Coastguard Worker use base::SafeDescriptor;
24*bb4ee6a4SAndroid Build Coastguard Worker use base::SendTube;
25*bb4ee6a4SAndroid Build Coastguard Worker use fnv::FnvHashMap;
26*bb4ee6a4SAndroid Build Coastguard Worker use libc::EEXIST;
27*bb4ee6a4SAndroid Build Coastguard Worker use libc::EFAULT;
28*bb4ee6a4SAndroid Build Coastguard Worker use libc::EINVAL;
29*bb4ee6a4SAndroid Build Coastguard Worker use libc::EIO;
30*bb4ee6a4SAndroid Build Coastguard Worker use libc::ENODEV;
31*bb4ee6a4SAndroid Build Coastguard Worker use libc::ENOENT;
32*bb4ee6a4SAndroid Build Coastguard Worker use libc::ENOSPC;
33*bb4ee6a4SAndroid Build Coastguard Worker use libc::ENOTSUP;
34*bb4ee6a4SAndroid Build Coastguard Worker use libc::EOVERFLOW;
35*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
36*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
37*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
38*bb4ee6a4SAndroid Build Coastguard Worker use winapi::shared::winerror::ERROR_BUSY;
39*bb4ee6a4SAndroid Build Coastguard Worker use winapi::shared::winerror::ERROR_SUCCESS;
40*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::memoryapi::OfferVirtualMemory;
41*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::memoryapi::ReclaimVirtualMemory;
42*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::memoryapi::VmOfferPriorityBelowNormal;
43*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::winnt::RtlZeroMemory;
44*bb4ee6a4SAndroid Build Coastguard Worker 
45*bb4ee6a4SAndroid Build Coastguard Worker use super::types::*;
46*bb4ee6a4SAndroid Build Coastguard Worker use super::*;
47*bb4ee6a4SAndroid Build Coastguard Worker use crate::host_phys_addr_bits;
48*bb4ee6a4SAndroid Build Coastguard Worker use crate::whpx::whpx_sys::*;
49*bb4ee6a4SAndroid Build Coastguard Worker use crate::BalloonEvent;
50*bb4ee6a4SAndroid Build Coastguard Worker use crate::ClockState;
51*bb4ee6a4SAndroid Build Coastguard Worker use crate::Datamatch;
52*bb4ee6a4SAndroid Build Coastguard Worker use crate::DeliveryMode;
53*bb4ee6a4SAndroid Build Coastguard Worker use crate::DestinationMode;
54*bb4ee6a4SAndroid Build Coastguard Worker use crate::DeviceKind;
55*bb4ee6a4SAndroid Build Coastguard Worker use crate::IoEventAddress;
56*bb4ee6a4SAndroid Build Coastguard Worker use crate::LapicState;
57*bb4ee6a4SAndroid Build Coastguard Worker use crate::MemCacheType;
58*bb4ee6a4SAndroid Build Coastguard Worker use crate::MemSlot;
59*bb4ee6a4SAndroid Build Coastguard Worker use crate::TriggerMode;
60*bb4ee6a4SAndroid Build Coastguard Worker use crate::VcpuX86_64;
61*bb4ee6a4SAndroid Build Coastguard Worker use crate::Vm;
62*bb4ee6a4SAndroid Build Coastguard Worker use crate::VmCap;
63*bb4ee6a4SAndroid Build Coastguard Worker use crate::VmX86_64;
64*bb4ee6a4SAndroid Build Coastguard Worker 
65*bb4ee6a4SAndroid Build Coastguard Worker pub struct WhpxVm {
66*bb4ee6a4SAndroid Build Coastguard Worker     whpx: Whpx,
67*bb4ee6a4SAndroid Build Coastguard Worker     // reference counted, since we need to implement try_clone or some variation.
68*bb4ee6a4SAndroid Build Coastguard Worker     // There is only ever 1 create/1 delete partition unlike dup/close handle variations.
69*bb4ee6a4SAndroid Build Coastguard Worker     vm_partition: Arc<SafePartition>,
70*bb4ee6a4SAndroid Build Coastguard Worker     guest_mem: GuestMemory,
71*bb4ee6a4SAndroid Build Coastguard Worker     mem_regions: Arc<Mutex<BTreeMap<MemSlot, (GuestAddress, Box<dyn MappedRegion>)>>>,
72*bb4ee6a4SAndroid Build Coastguard Worker     /// A min heap of MemSlot numbers that were used and then removed and can now be re-used
73*bb4ee6a4SAndroid Build Coastguard Worker     mem_slot_gaps: Arc<Mutex<BinaryHeap<Reverse<MemSlot>>>>,
74*bb4ee6a4SAndroid Build Coastguard Worker     // WHPX's implementation of ioevents makes several assumptions about how crosvm uses ioevents:
75*bb4ee6a4SAndroid Build Coastguard Worker     //   1. All ioevents are registered during device setup, and thus can be cloned when the vm is
76*bb4ee6a4SAndroid Build Coastguard Worker     //      cloned instead of locked in an Arc<Mutex<>>. This will make handling ioevents in each
77*bb4ee6a4SAndroid Build Coastguard Worker     //      vcpu thread easier because no locks will need to be acquired.
78*bb4ee6a4SAndroid Build Coastguard Worker     //   2. All ioevents use Datamatch::AnyLength. We don't bother checking the datamatch, which
79*bb4ee6a4SAndroid Build Coastguard Worker     //      will make this faster.
80*bb4ee6a4SAndroid Build Coastguard Worker     //   3. We only ever register one eventfd to each address. This simplifies our data structure.
81*bb4ee6a4SAndroid Build Coastguard Worker     ioevents: FnvHashMap<IoEventAddress, Event>,
82*bb4ee6a4SAndroid Build Coastguard Worker     // Tube to send events to control.
83*bb4ee6a4SAndroid Build Coastguard Worker     vm_evt_wrtube: Option<SendTube>,
84*bb4ee6a4SAndroid Build Coastguard Worker }
85*bb4ee6a4SAndroid Build Coastguard Worker 
86*bb4ee6a4SAndroid Build Coastguard Worker impl WhpxVm {
new( whpx: &Whpx, cpu_count: usize, guest_mem: GuestMemory, cpuid: CpuId, apic_emulation: bool, vm_evt_wrtube: Option<SendTube>, ) -> WhpxResult<WhpxVm>87*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(
88*bb4ee6a4SAndroid Build Coastguard Worker         whpx: &Whpx,
89*bb4ee6a4SAndroid Build Coastguard Worker         cpu_count: usize,
90*bb4ee6a4SAndroid Build Coastguard Worker         guest_mem: GuestMemory,
91*bb4ee6a4SAndroid Build Coastguard Worker         cpuid: CpuId,
92*bb4ee6a4SAndroid Build Coastguard Worker         apic_emulation: bool,
93*bb4ee6a4SAndroid Build Coastguard Worker         vm_evt_wrtube: Option<SendTube>,
94*bb4ee6a4SAndroid Build Coastguard Worker     ) -> WhpxResult<WhpxVm> {
95*bb4ee6a4SAndroid Build Coastguard Worker         let partition = SafePartition::new()?;
96*bb4ee6a4SAndroid Build Coastguard Worker         // setup partition defaults.
97*bb4ee6a4SAndroid Build Coastguard Worker         let mut property: WHV_PARTITION_PROPERTY = Default::default();
98*bb4ee6a4SAndroid Build Coastguard Worker         property.ProcessorCount = cpu_count as u32;
99*bb4ee6a4SAndroid Build Coastguard Worker         // safe because we own this partition, and the partition property is allocated on the stack.
100*bb4ee6a4SAndroid Build Coastguard Worker         check_whpx!(unsafe {
101*bb4ee6a4SAndroid Build Coastguard Worker             WHvSetPartitionProperty(
102*bb4ee6a4SAndroid Build Coastguard Worker                 partition.partition,
103*bb4ee6a4SAndroid Build Coastguard Worker                 WHV_PARTITION_PROPERTY_CODE_WHvPartitionPropertyCodeProcessorCount,
104*bb4ee6a4SAndroid Build Coastguard Worker                 &property as *const _ as *const c_void,
105*bb4ee6a4SAndroid Build Coastguard Worker                 std::mem::size_of::<WHV_PARTITION_PROPERTY>() as UINT32,
106*bb4ee6a4SAndroid Build Coastguard Worker             )
107*bb4ee6a4SAndroid Build Coastguard Worker         })
108*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(WhpxError::SetProcessorCount)?;
109*bb4ee6a4SAndroid Build Coastguard Worker 
110*bb4ee6a4SAndroid Build Coastguard Worker         // Pre-set any cpuid results in cpuid.
111*bb4ee6a4SAndroid Build Coastguard Worker         let mut cpuid_results: Vec<WHV_X64_CPUID_RESULT> = cpuid
112*bb4ee6a4SAndroid Build Coastguard Worker             .cpu_id_entries
113*bb4ee6a4SAndroid Build Coastguard Worker             .iter()
114*bb4ee6a4SAndroid Build Coastguard Worker             .map(WHV_X64_CPUID_RESULT::from)
115*bb4ee6a4SAndroid Build Coastguard Worker             .collect();
116*bb4ee6a4SAndroid Build Coastguard Worker 
117*bb4ee6a4SAndroid Build Coastguard Worker         // Leaf HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS tells linux that it's running under Hyper-V.
118*bb4ee6a4SAndroid Build Coastguard Worker         cpuid_results.push(WHV_X64_CPUID_RESULT {
119*bb4ee6a4SAndroid Build Coastguard Worker             Function: HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
120*bb4ee6a4SAndroid Build Coastguard Worker             Reserved: [0u32; 3],
121*bb4ee6a4SAndroid Build Coastguard Worker             // HYPERV_CPUID_MIN is the minimum leaf that we need to support returning to the guest
122*bb4ee6a4SAndroid Build Coastguard Worker             Eax: HYPERV_CPUID_MIN,
123*bb4ee6a4SAndroid Build Coastguard Worker             Ebx: u32::from_le_bytes([b'M', b'i', b'c', b'r']),
124*bb4ee6a4SAndroid Build Coastguard Worker             Ecx: u32::from_le_bytes([b'o', b's', b'o', b'f']),
125*bb4ee6a4SAndroid Build Coastguard Worker             Edx: u32::from_le_bytes([b't', b' ', b'H', b'v']),
126*bb4ee6a4SAndroid Build Coastguard Worker         });
127*bb4ee6a4SAndroid Build Coastguard Worker 
128*bb4ee6a4SAndroid Build Coastguard Worker         // HYPERV_CPUID_FEATURES leaf tells linux which Hyper-V features we support
129*bb4ee6a4SAndroid Build Coastguard Worker         cpuid_results.push(WHV_X64_CPUID_RESULT {
130*bb4ee6a4SAndroid Build Coastguard Worker             Function: HYPERV_CPUID_FEATURES,
131*bb4ee6a4SAndroid Build Coastguard Worker             Reserved: [0u32; 3],
132*bb4ee6a4SAndroid Build Coastguard Worker             // We only support frequency MSRs and the HV_ACCESS_TSC_INVARIANT feature, which means
133*bb4ee6a4SAndroid Build Coastguard Worker             // TSC scaling/offseting is handled in hardware, not the guest.
134*bb4ee6a4SAndroid Build Coastguard Worker             Eax: HV_ACCESS_FREQUENCY_MSRS
135*bb4ee6a4SAndroid Build Coastguard Worker                 | HV_ACCESS_TSC_INVARIANT
136*bb4ee6a4SAndroid Build Coastguard Worker                 | HV_MSR_REFERENCE_TSC_AVAILABLE,
137*bb4ee6a4SAndroid Build Coastguard Worker             Ebx: 0,
138*bb4ee6a4SAndroid Build Coastguard Worker             Edx: HV_FEATURE_FREQUENCY_MSRS_AVAILABLE,
139*bb4ee6a4SAndroid Build Coastguard Worker             Ecx: 0,
140*bb4ee6a4SAndroid Build Coastguard Worker         });
141*bb4ee6a4SAndroid Build Coastguard Worker 
142*bb4ee6a4SAndroid Build Coastguard Worker         // safe because we own this partition, and the cpuid_results vec is local to this function.
143*bb4ee6a4SAndroid Build Coastguard Worker         check_whpx!(unsafe {
144*bb4ee6a4SAndroid Build Coastguard Worker             WHvSetPartitionProperty(
145*bb4ee6a4SAndroid Build Coastguard Worker                 partition.partition,
146*bb4ee6a4SAndroid Build Coastguard Worker                 WHV_PARTITION_PROPERTY_CODE_WHvPartitionPropertyCodeCpuidResultList,
147*bb4ee6a4SAndroid Build Coastguard Worker                 cpuid_results.as_ptr() as *const _ as *const c_void,
148*bb4ee6a4SAndroid Build Coastguard Worker                 (std::mem::size_of::<WHV_X64_CPUID_RESULT>() * cpuid_results.len()) as UINT32,
149*bb4ee6a4SAndroid Build Coastguard Worker             )
150*bb4ee6a4SAndroid Build Coastguard Worker         })
151*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(WhpxError::SetCpuidResultList)?;
152*bb4ee6a4SAndroid Build Coastguard Worker 
153*bb4ee6a4SAndroid Build Coastguard Worker         // Setup exiting for cpuid leaves that we want crosvm to adjust, but that we can't pre-set.
154*bb4ee6a4SAndroid Build Coastguard Worker         // We can't pre-set leaves that rely on irqchip information, and we cannot pre-set leaves
155*bb4ee6a4SAndroid Build Coastguard Worker         // that return different results per-cpu.
156*bb4ee6a4SAndroid Build Coastguard Worker         let exit_list: Vec<u32> = vec![0x1, 0x4, 0xB, 0x1F, 0x15];
157*bb4ee6a4SAndroid Build Coastguard Worker         // safe because we own this partition, and the exit_list vec local to this function.
158*bb4ee6a4SAndroid Build Coastguard Worker         check_whpx!(unsafe {
159*bb4ee6a4SAndroid Build Coastguard Worker             WHvSetPartitionProperty(
160*bb4ee6a4SAndroid Build Coastguard Worker                 partition.partition,
161*bb4ee6a4SAndroid Build Coastguard Worker                 WHV_PARTITION_PROPERTY_CODE_WHvPartitionPropertyCodeCpuidExitList,
162*bb4ee6a4SAndroid Build Coastguard Worker                 exit_list.as_ptr() as *const _ as *const c_void,
163*bb4ee6a4SAndroid Build Coastguard Worker                 (std::mem::size_of::<u32>() * exit_list.len()) as UINT32,
164*bb4ee6a4SAndroid Build Coastguard Worker             )
165*bb4ee6a4SAndroid Build Coastguard Worker         })
166*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(WhpxError::SetCpuidExitList)?;
167*bb4ee6a4SAndroid Build Coastguard Worker 
168*bb4ee6a4SAndroid Build Coastguard Worker         // Setup exits for CPUID instruction.
169*bb4ee6a4SAndroid Build Coastguard Worker         let mut property: WHV_PARTITION_PROPERTY = Default::default();
170*bb4ee6a4SAndroid Build Coastguard Worker         // safe because we own this partition, and the partition property is allocated on the stack.
171*bb4ee6a4SAndroid Build Coastguard Worker         unsafe {
172*bb4ee6a4SAndroid Build Coastguard Worker             property
173*bb4ee6a4SAndroid Build Coastguard Worker                 .ExtendedVmExits
174*bb4ee6a4SAndroid Build Coastguard Worker                 .__bindgen_anon_1
175*bb4ee6a4SAndroid Build Coastguard Worker                 .set_X64CpuidExit(1);
176*bb4ee6a4SAndroid Build Coastguard Worker             // X64MsrExit essentially causes WHPX to exit to crosvm when it would normally fail an
177*bb4ee6a4SAndroid Build Coastguard Worker             // MSR access and inject a GP fault. Crosvm, in turn, now handles select MSR accesses
178*bb4ee6a4SAndroid Build Coastguard Worker             // related to Hyper-V (see the handle_msr_* functions in vcpu.rs) and injects a GP
179*bb4ee6a4SAndroid Build Coastguard Worker             // fault for any unhandled MSR accesses.
180*bb4ee6a4SAndroid Build Coastguard Worker             property.ExtendedVmExits.__bindgen_anon_1.set_X64MsrExit(1);
181*bb4ee6a4SAndroid Build Coastguard Worker         }
182*bb4ee6a4SAndroid Build Coastguard Worker         // safe because we own this partition, and the partition property is allocated on the stack.
183*bb4ee6a4SAndroid Build Coastguard Worker         check_whpx!(unsafe {
184*bb4ee6a4SAndroid Build Coastguard Worker             WHvSetPartitionProperty(
185*bb4ee6a4SAndroid Build Coastguard Worker                 partition.partition,
186*bb4ee6a4SAndroid Build Coastguard Worker                 WHV_PARTITION_PROPERTY_CODE_WHvPartitionPropertyCodeExtendedVmExits,
187*bb4ee6a4SAndroid Build Coastguard Worker                 &property as *const _ as *const c_void,
188*bb4ee6a4SAndroid Build Coastguard Worker                 std::mem::size_of::<WHV_PARTITION_PROPERTY>() as UINT32,
189*bb4ee6a4SAndroid Build Coastguard Worker             )
190*bb4ee6a4SAndroid Build Coastguard Worker         })
191*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(WhpxError::SetExtendedVmExits)?;
192*bb4ee6a4SAndroid Build Coastguard Worker 
193*bb4ee6a4SAndroid Build Coastguard Worker         if apic_emulation && !Whpx::check_whpx_feature(WhpxFeature::LocalApicEmulation)? {
194*bb4ee6a4SAndroid Build Coastguard Worker             return Err(WhpxError::LocalApicEmulationNotSupported);
195*bb4ee6a4SAndroid Build Coastguard Worker         }
196*bb4ee6a4SAndroid Build Coastguard Worker 
197*bb4ee6a4SAndroid Build Coastguard Worker         // Setup apic emulation mode
198*bb4ee6a4SAndroid Build Coastguard Worker         let mut property: WHV_PARTITION_PROPERTY = Default::default();
199*bb4ee6a4SAndroid Build Coastguard Worker         property.LocalApicEmulationMode = if apic_emulation {
200*bb4ee6a4SAndroid Build Coastguard Worker             // TODO(b/180966070): figure out if x2apic emulation mode is available on the host and
201*bb4ee6a4SAndroid Build Coastguard Worker             // enable it if it is.
202*bb4ee6a4SAndroid Build Coastguard Worker             WHV_X64_LOCAL_APIC_EMULATION_MODE_WHvX64LocalApicEmulationModeXApic
203*bb4ee6a4SAndroid Build Coastguard Worker         } else {
204*bb4ee6a4SAndroid Build Coastguard Worker             WHV_X64_LOCAL_APIC_EMULATION_MODE_WHvX64LocalApicEmulationModeNone
205*bb4ee6a4SAndroid Build Coastguard Worker         };
206*bb4ee6a4SAndroid Build Coastguard Worker 
207*bb4ee6a4SAndroid Build Coastguard Worker         // safe because we own this partition, and the partition property is allocated on the stack.
208*bb4ee6a4SAndroid Build Coastguard Worker         check_whpx!(unsafe {
209*bb4ee6a4SAndroid Build Coastguard Worker             WHvSetPartitionProperty(
210*bb4ee6a4SAndroid Build Coastguard Worker                 partition.partition,
211*bb4ee6a4SAndroid Build Coastguard Worker                 WHV_PARTITION_PROPERTY_CODE_WHvPartitionPropertyCodeLocalApicEmulationMode,
212*bb4ee6a4SAndroid Build Coastguard Worker                 &property as *const _ as *const c_void,
213*bb4ee6a4SAndroid Build Coastguard Worker                 std::mem::size_of::<WHV_PARTITION_PROPERTY>() as UINT32,
214*bb4ee6a4SAndroid Build Coastguard Worker             )
215*bb4ee6a4SAndroid Build Coastguard Worker         })
216*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(WhpxError::SetLocalApicEmulationMode)?;
217*bb4ee6a4SAndroid Build Coastguard Worker 
218*bb4ee6a4SAndroid Build Coastguard Worker         // safe because we own this partition
219*bb4ee6a4SAndroid Build Coastguard Worker         check_whpx!(unsafe { WHvSetupPartition(partition.partition) })
220*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(WhpxError::SetupPartition)?;
221*bb4ee6a4SAndroid Build Coastguard Worker 
222*bb4ee6a4SAndroid Build Coastguard Worker         for region in guest_mem.regions() {
223*bb4ee6a4SAndroid Build Coastguard Worker             unsafe {
224*bb4ee6a4SAndroid Build Coastguard Worker                 // Safe because the guest regions are guaranteed not to overlap.
225*bb4ee6a4SAndroid Build Coastguard Worker                 set_user_memory_region(
226*bb4ee6a4SAndroid Build Coastguard Worker                     &partition,
227*bb4ee6a4SAndroid Build Coastguard Worker                     false, // read_only
228*bb4ee6a4SAndroid Build Coastguard Worker                     false, // track dirty pages
229*bb4ee6a4SAndroid Build Coastguard Worker                     region.guest_addr.offset(),
230*bb4ee6a4SAndroid Build Coastguard Worker                     region.size as u64,
231*bb4ee6a4SAndroid Build Coastguard Worker                     region.host_addr as *mut u8,
232*bb4ee6a4SAndroid Build Coastguard Worker                 )
233*bb4ee6a4SAndroid Build Coastguard Worker             }
234*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(WhpxError::MapGpaRange)?;
235*bb4ee6a4SAndroid Build Coastguard Worker         }
236*bb4ee6a4SAndroid Build Coastguard Worker 
237*bb4ee6a4SAndroid Build Coastguard Worker         Ok(WhpxVm {
238*bb4ee6a4SAndroid Build Coastguard Worker             whpx: whpx.clone(),
239*bb4ee6a4SAndroid Build Coastguard Worker             vm_partition: Arc::new(partition),
240*bb4ee6a4SAndroid Build Coastguard Worker             guest_mem,
241*bb4ee6a4SAndroid Build Coastguard Worker             mem_regions: Arc::new(Mutex::new(BTreeMap::new())),
242*bb4ee6a4SAndroid Build Coastguard Worker             mem_slot_gaps: Arc::new(Mutex::new(BinaryHeap::new())),
243*bb4ee6a4SAndroid Build Coastguard Worker             ioevents: FnvHashMap::default(),
244*bb4ee6a4SAndroid Build Coastguard Worker             vm_evt_wrtube,
245*bb4ee6a4SAndroid Build Coastguard Worker         })
246*bb4ee6a4SAndroid Build Coastguard Worker     }
247*bb4ee6a4SAndroid Build Coastguard Worker 
248*bb4ee6a4SAndroid Build Coastguard Worker     /// Get the current state of the specified VCPU's local APIC
get_vcpu_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>249*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_vcpu_lapic_state(&self, vcpu_id: usize) -> Result<LapicState> {
250*bb4ee6a4SAndroid Build Coastguard Worker         let buffer = WhpxLapicState { regs: [0u32; 1024] };
251*bb4ee6a4SAndroid Build Coastguard Worker         let mut written_size = 0u32;
252*bb4ee6a4SAndroid Build Coastguard Worker         let size = std::mem::size_of::<WhpxLapicState>();
253*bb4ee6a4SAndroid Build Coastguard Worker 
254*bb4ee6a4SAndroid Build Coastguard Worker         check_whpx!(unsafe {
255*bb4ee6a4SAndroid Build Coastguard Worker             WHvGetVirtualProcessorInterruptControllerState(
256*bb4ee6a4SAndroid Build Coastguard Worker                 self.vm_partition.partition,
257*bb4ee6a4SAndroid Build Coastguard Worker                 vcpu_id as u32,
258*bb4ee6a4SAndroid Build Coastguard Worker                 buffer.regs.as_ptr() as *mut c_void,
259*bb4ee6a4SAndroid Build Coastguard Worker                 size as u32,
260*bb4ee6a4SAndroid Build Coastguard Worker                 &mut written_size,
261*bb4ee6a4SAndroid Build Coastguard Worker             )
262*bb4ee6a4SAndroid Build Coastguard Worker         })?;
263*bb4ee6a4SAndroid Build Coastguard Worker 
264*bb4ee6a4SAndroid Build Coastguard Worker         Ok(LapicState::from(&buffer))
265*bb4ee6a4SAndroid Build Coastguard Worker     }
266*bb4ee6a4SAndroid Build Coastguard Worker 
267*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the current state of the specified VCPU's local APIC
set_vcpu_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>268*bb4ee6a4SAndroid Build Coastguard Worker     pub fn set_vcpu_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()> {
269*bb4ee6a4SAndroid Build Coastguard Worker         let buffer = WhpxLapicState::from(state);
270*bb4ee6a4SAndroid Build Coastguard Worker         check_whpx!(unsafe {
271*bb4ee6a4SAndroid Build Coastguard Worker             WHvSetVirtualProcessorInterruptControllerState(
272*bb4ee6a4SAndroid Build Coastguard Worker                 self.vm_partition.partition,
273*bb4ee6a4SAndroid Build Coastguard Worker                 vcpu_id as u32,
274*bb4ee6a4SAndroid Build Coastguard Worker                 buffer.regs.as_ptr() as *mut c_void,
275*bb4ee6a4SAndroid Build Coastguard Worker                 std::mem::size_of::<WhpxLapicState>() as u32,
276*bb4ee6a4SAndroid Build Coastguard Worker             )
277*bb4ee6a4SAndroid Build Coastguard Worker         })?;
278*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
279*bb4ee6a4SAndroid Build Coastguard Worker     }
280*bb4ee6a4SAndroid Build Coastguard Worker 
281*bb4ee6a4SAndroid Build Coastguard Worker     /// Request an interrupt be delivered to one or more virtualized interrupt controllers. This
282*bb4ee6a4SAndroid Build Coastguard Worker     /// should only be used with ApicEmulationModeXApic or ApicEmulationModeX2Apic.
request_interrupt( &self, vector: u8, dest_id: u8, dest_mode: DestinationMode, trigger: TriggerMode, delivery: DeliveryMode, ) -> Result<()>283*bb4ee6a4SAndroid Build Coastguard Worker     pub fn request_interrupt(
284*bb4ee6a4SAndroid Build Coastguard Worker         &self,
285*bb4ee6a4SAndroid Build Coastguard Worker         vector: u8,
286*bb4ee6a4SAndroid Build Coastguard Worker         dest_id: u8,
287*bb4ee6a4SAndroid Build Coastguard Worker         dest_mode: DestinationMode,
288*bb4ee6a4SAndroid Build Coastguard Worker         trigger: TriggerMode,
289*bb4ee6a4SAndroid Build Coastguard Worker         delivery: DeliveryMode,
290*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
291*bb4ee6a4SAndroid Build Coastguard Worker         // The WHV_INTERRUPT_CONTROL does not seem to support the dest_shorthand
292*bb4ee6a4SAndroid Build Coastguard Worker         let mut interrupt = WHV_INTERRUPT_CONTROL {
293*bb4ee6a4SAndroid Build Coastguard Worker             Destination: dest_id as u32,
294*bb4ee6a4SAndroid Build Coastguard Worker             Vector: vector as u32,
295*bb4ee6a4SAndroid Build Coastguard Worker             ..Default::default()
296*bb4ee6a4SAndroid Build Coastguard Worker         };
297*bb4ee6a4SAndroid Build Coastguard Worker         interrupt.set_DestinationMode(match dest_mode {
298*bb4ee6a4SAndroid Build Coastguard Worker             DestinationMode::Physical => {
299*bb4ee6a4SAndroid Build Coastguard Worker                 WHV_INTERRUPT_DESTINATION_MODE_WHvX64InterruptDestinationModePhysical
300*bb4ee6a4SAndroid Build Coastguard Worker             }
301*bb4ee6a4SAndroid Build Coastguard Worker             DestinationMode::Logical => {
302*bb4ee6a4SAndroid Build Coastguard Worker                 WHV_INTERRUPT_DESTINATION_MODE_WHvX64InterruptDestinationModeLogical
303*bb4ee6a4SAndroid Build Coastguard Worker             }
304*bb4ee6a4SAndroid Build Coastguard Worker         } as u64);
305*bb4ee6a4SAndroid Build Coastguard Worker         interrupt.set_TriggerMode(match trigger {
306*bb4ee6a4SAndroid Build Coastguard Worker             TriggerMode::Edge => WHV_INTERRUPT_TRIGGER_MODE_WHvX64InterruptTriggerModeEdge,
307*bb4ee6a4SAndroid Build Coastguard Worker             TriggerMode::Level => WHV_INTERRUPT_TRIGGER_MODE_WHvX64InterruptTriggerModeLevel,
308*bb4ee6a4SAndroid Build Coastguard Worker         } as u64);
309*bb4ee6a4SAndroid Build Coastguard Worker         interrupt.set_Type(match delivery {
310*bb4ee6a4SAndroid Build Coastguard Worker             DeliveryMode::Fixed => WHV_INTERRUPT_TYPE_WHvX64InterruptTypeFixed,
311*bb4ee6a4SAndroid Build Coastguard Worker             DeliveryMode::Lowest => WHV_INTERRUPT_TYPE_WHvX64InterruptTypeLowestPriority,
312*bb4ee6a4SAndroid Build Coastguard Worker             DeliveryMode::SMI => {
313*bb4ee6a4SAndroid Build Coastguard Worker                 error!("WHPX does not support requesting an SMI");
314*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(Error::new(ENOTSUP));
315*bb4ee6a4SAndroid Build Coastguard Worker             }
316*bb4ee6a4SAndroid Build Coastguard Worker             DeliveryMode::RemoteRead => {
317*bb4ee6a4SAndroid Build Coastguard Worker                 // This is also no longer supported by intel.
318*bb4ee6a4SAndroid Build Coastguard Worker                 error!("Remote Read interrupts are not supported by WHPX");
319*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(Error::new(ENOTSUP));
320*bb4ee6a4SAndroid Build Coastguard Worker             }
321*bb4ee6a4SAndroid Build Coastguard Worker             DeliveryMode::NMI => WHV_INTERRUPT_TYPE_WHvX64InterruptTypeNmi,
322*bb4ee6a4SAndroid Build Coastguard Worker             DeliveryMode::Init => WHV_INTERRUPT_TYPE_WHvX64InterruptTypeInit,
323*bb4ee6a4SAndroid Build Coastguard Worker             DeliveryMode::Startup => WHV_INTERRUPT_TYPE_WHvX64InterruptTypeSipi,
324*bb4ee6a4SAndroid Build Coastguard Worker             DeliveryMode::External => {
325*bb4ee6a4SAndroid Build Coastguard Worker                 error!("WHPX does not support requesting an external interrupt");
326*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(Error::new(ENOTSUP));
327*bb4ee6a4SAndroid Build Coastguard Worker             }
328*bb4ee6a4SAndroid Build Coastguard Worker         } as u64);
329*bb4ee6a4SAndroid Build Coastguard Worker 
330*bb4ee6a4SAndroid Build Coastguard Worker         check_whpx!(unsafe {
331*bb4ee6a4SAndroid Build Coastguard Worker             WHvRequestInterrupt(
332*bb4ee6a4SAndroid Build Coastguard Worker                 self.vm_partition.partition,
333*bb4ee6a4SAndroid Build Coastguard Worker                 &interrupt,
334*bb4ee6a4SAndroid Build Coastguard Worker                 std::mem::size_of::<WHV_INTERRUPT_CONTROL>() as u32,
335*bb4ee6a4SAndroid Build Coastguard Worker             )
336*bb4ee6a4SAndroid Build Coastguard Worker         })
337*bb4ee6a4SAndroid Build Coastguard Worker     }
338*bb4ee6a4SAndroid Build Coastguard Worker 
339*bb4ee6a4SAndroid Build Coastguard Worker     /// In order to fully unmap a memory range such that the host can reclaim the memory,
340*bb4ee6a4SAndroid Build Coastguard Worker     /// we unmap it from the hypervisor partition, and then mark crosvm's process as uninterested
341*bb4ee6a4SAndroid Build Coastguard Worker     /// in the memory.
342*bb4ee6a4SAndroid Build Coastguard Worker     ///
343*bb4ee6a4SAndroid Build Coastguard Worker     /// This will make crosvm unable to access the memory, and allow Windows to reclaim it for other
344*bb4ee6a4SAndroid Build Coastguard Worker     /// uses when memory is in demand.
handle_inflate(&mut self, guest_address: GuestAddress, size: u64) -> Result<()>345*bb4ee6a4SAndroid Build Coastguard Worker     fn handle_inflate(&mut self, guest_address: GuestAddress, size: u64) -> Result<()> {
346*bb4ee6a4SAndroid Build Coastguard Worker         info!(
347*bb4ee6a4SAndroid Build Coastguard Worker             "Balloon: Requested WHPX unmap of addr: {:?}, size: {:?}",
348*bb4ee6a4SAndroid Build Coastguard Worker             guest_address, size
349*bb4ee6a4SAndroid Build Coastguard Worker         );
350*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because WHPX does proper error checking, even if an out-of-bounds address is
351*bb4ee6a4SAndroid Build Coastguard Worker         // provided.
352*bb4ee6a4SAndroid Build Coastguard Worker         unsafe {
353*bb4ee6a4SAndroid Build Coastguard Worker             check_whpx!(WHvUnmapGpaRange(
354*bb4ee6a4SAndroid Build Coastguard Worker                 self.vm_partition.partition,
355*bb4ee6a4SAndroid Build Coastguard Worker                 guest_address.offset(),
356*bb4ee6a4SAndroid Build Coastguard Worker                 size,
357*bb4ee6a4SAndroid Build Coastguard Worker             ))?;
358*bb4ee6a4SAndroid Build Coastguard Worker         }
359*bb4ee6a4SAndroid Build Coastguard Worker 
360*bb4ee6a4SAndroid Build Coastguard Worker         let host_address = self
361*bb4ee6a4SAndroid Build Coastguard Worker             .guest_mem
362*bb4ee6a4SAndroid Build Coastguard Worker             .get_host_address(guest_address)
363*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|_| Error::new(1))? as *mut c_void;
364*bb4ee6a4SAndroid Build Coastguard Worker 
365*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because we have just successfully unmapped this range from the
366*bb4ee6a4SAndroid Build Coastguard Worker         // guest partition, so we know it's unused.
367*bb4ee6a4SAndroid Build Coastguard Worker         let result =
368*bb4ee6a4SAndroid Build Coastguard Worker             unsafe { OfferVirtualMemory(host_address, size as usize, VmOfferPriorityBelowNormal) };
369*bb4ee6a4SAndroid Build Coastguard Worker 
370*bb4ee6a4SAndroid Build Coastguard Worker         if result != ERROR_SUCCESS {
371*bb4ee6a4SAndroid Build Coastguard Worker             let err = Error::new(result);
372*bb4ee6a4SAndroid Build Coastguard Worker             error!("Freeing memory failed with error: {}", err);
373*bb4ee6a4SAndroid Build Coastguard Worker             return Err(err);
374*bb4ee6a4SAndroid Build Coastguard Worker         }
375*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
376*bb4ee6a4SAndroid Build Coastguard Worker     }
377*bb4ee6a4SAndroid Build Coastguard Worker 
378*bb4ee6a4SAndroid Build Coastguard Worker     /// Remap memory that has previously been unmapped with #handle_inflate. Note
379*bb4ee6a4SAndroid Build Coastguard Worker     /// that attempts to remap pages that were not previously unmapped, or addresses that are not
380*bb4ee6a4SAndroid Build Coastguard Worker     /// page-aligned, will result in failure.
381*bb4ee6a4SAndroid Build Coastguard Worker     ///
382*bb4ee6a4SAndroid Build Coastguard Worker     /// To do this, reclaim the memory from Windows first, then remap it into the hypervisor
383*bb4ee6a4SAndroid Build Coastguard Worker     /// partition. Remapped memory has no guarantee of content, and the guest should not expect
384*bb4ee6a4SAndroid Build Coastguard Worker     /// it to.
handle_deflate(&mut self, guest_address: GuestAddress, size: u64) -> Result<()>385*bb4ee6a4SAndroid Build Coastguard Worker     fn handle_deflate(&mut self, guest_address: GuestAddress, size: u64) -> Result<()> {
386*bb4ee6a4SAndroid Build Coastguard Worker         info!(
387*bb4ee6a4SAndroid Build Coastguard Worker             "Balloon: Requested WHPX unmap of addr: {:?}, size: {:?}",
388*bb4ee6a4SAndroid Build Coastguard Worker             guest_address, size
389*bb4ee6a4SAndroid Build Coastguard Worker         );
390*bb4ee6a4SAndroid Build Coastguard Worker 
391*bb4ee6a4SAndroid Build Coastguard Worker         let host_address = self
392*bb4ee6a4SAndroid Build Coastguard Worker             .guest_mem
393*bb4ee6a4SAndroid Build Coastguard Worker             .get_host_address(guest_address)
394*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|_| Error::new(1))? as *const c_void;
395*bb4ee6a4SAndroid Build Coastguard Worker 
396*bb4ee6a4SAndroid Build Coastguard Worker         // Note that we aren't doing any validation here that this range was previously unmapped.
397*bb4ee6a4SAndroid Build Coastguard Worker         // However, we can avoid that expensive validation by relying on Windows error checking for
398*bb4ee6a4SAndroid Build Coastguard Worker         // ReclaimVirtualMemory. The call will fail if:
399*bb4ee6a4SAndroid Build Coastguard Worker         // - If the range is not currently "offered"
400*bb4ee6a4SAndroid Build Coastguard Worker         // - The range is outside of current guest mem (GuestMemory will fail to convert the
401*bb4ee6a4SAndroid Build Coastguard Worker         //   address)
402*bb4ee6a4SAndroid Build Coastguard Worker         // In short, security is guaranteed by ensuring the guest can never reclaim ranges it
403*bb4ee6a4SAndroid Build Coastguard Worker         // hadn't previously forfeited (and even then, the contents will be zeroed).
404*bb4ee6a4SAndroid Build Coastguard Worker         //
405*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because the memory ranges in question are managed by Windows, not Rust.
406*bb4ee6a4SAndroid Build Coastguard Worker         // Also, ReclaimVirtualMemory has built-in error checking for bad parameters.
407*bb4ee6a4SAndroid Build Coastguard Worker         let result = unsafe { ReclaimVirtualMemory(host_address, size as usize) };
408*bb4ee6a4SAndroid Build Coastguard Worker 
409*bb4ee6a4SAndroid Build Coastguard Worker         if result == ERROR_BUSY || result == ERROR_SUCCESS {
410*bb4ee6a4SAndroid Build Coastguard Worker             // In either of these cases, the contents of the reclaimed memory
411*bb4ee6a4SAndroid Build Coastguard Worker             // are preserved or undefined. Regardless, zero the memory
412*bb4ee6a4SAndroid Build Coastguard Worker             // to ensure no unintentional memory contents are shared.
413*bb4ee6a4SAndroid Build Coastguard Worker             //
414*bb4ee6a4SAndroid Build Coastguard Worker             // Safe because we just reclaimed the region in question and haven't yet remapped
415*bb4ee6a4SAndroid Build Coastguard Worker             // it to the guest partition, so we know it's unused.
416*bb4ee6a4SAndroid Build Coastguard Worker             unsafe { RtlZeroMemory(host_address as RawDescriptor, size as usize) };
417*bb4ee6a4SAndroid Build Coastguard Worker         } else {
418*bb4ee6a4SAndroid Build Coastguard Worker             let err = Error::new(result);
419*bb4ee6a4SAndroid Build Coastguard Worker             error!("Reclaiming memory failed with error: {}", err);
420*bb4ee6a4SAndroid Build Coastguard Worker             return Err(err);
421*bb4ee6a4SAndroid Build Coastguard Worker         }
422*bb4ee6a4SAndroid Build Coastguard Worker 
423*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because no-overlap is guaranteed by the success of ReclaimVirtualMemory,
424*bb4ee6a4SAndroid Build Coastguard Worker         // Which would fail if it was called on areas which were not unmapped.
425*bb4ee6a4SAndroid Build Coastguard Worker         unsafe {
426*bb4ee6a4SAndroid Build Coastguard Worker             set_user_memory_region(
427*bb4ee6a4SAndroid Build Coastguard Worker                 &self.vm_partition,
428*bb4ee6a4SAndroid Build Coastguard Worker                 false, // read_only
429*bb4ee6a4SAndroid Build Coastguard Worker                 false, // track dirty pages
430*bb4ee6a4SAndroid Build Coastguard Worker                 guest_address.offset(),
431*bb4ee6a4SAndroid Build Coastguard Worker                 size,
432*bb4ee6a4SAndroid Build Coastguard Worker                 host_address as *mut u8,
433*bb4ee6a4SAndroid Build Coastguard Worker             )
434*bb4ee6a4SAndroid Build Coastguard Worker         }
435*bb4ee6a4SAndroid Build Coastguard Worker     }
436*bb4ee6a4SAndroid Build Coastguard Worker }
437*bb4ee6a4SAndroid Build Coastguard Worker 
438*bb4ee6a4SAndroid Build Coastguard Worker // Wrapper around WHvMapGpaRange, which creates, modifies, or deletes a mapping
439*bb4ee6a4SAndroid Build Coastguard Worker // from guest physical to host user pages.
440*bb4ee6a4SAndroid Build Coastguard Worker //
441*bb4ee6a4SAndroid Build Coastguard Worker // Safe when the guest regions are guaranteed not to overlap.
set_user_memory_region( partition: &SafePartition, read_only: bool, track_dirty_pages: bool, guest_addr: u64, memory_size: u64, userspace_addr: *mut u8, ) -> Result<()>442*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn set_user_memory_region(
443*bb4ee6a4SAndroid Build Coastguard Worker     partition: &SafePartition,
444*bb4ee6a4SAndroid Build Coastguard Worker     read_only: bool,
445*bb4ee6a4SAndroid Build Coastguard Worker     track_dirty_pages: bool,
446*bb4ee6a4SAndroid Build Coastguard Worker     guest_addr: u64,
447*bb4ee6a4SAndroid Build Coastguard Worker     memory_size: u64,
448*bb4ee6a4SAndroid Build Coastguard Worker     userspace_addr: *mut u8,
449*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
450*bb4ee6a4SAndroid Build Coastguard Worker     let mut flags = WHV_MAP_GPA_RANGE_FLAGS_WHvMapGpaRangeFlagRead
451*bb4ee6a4SAndroid Build Coastguard Worker         | WHV_MAP_GPA_RANGE_FLAGS_WHvMapGpaRangeFlagExecute;
452*bb4ee6a4SAndroid Build Coastguard Worker     if !read_only {
453*bb4ee6a4SAndroid Build Coastguard Worker         flags |= WHV_MAP_GPA_RANGE_FLAGS_WHvMapGpaRangeFlagWrite
454*bb4ee6a4SAndroid Build Coastguard Worker     }
455*bb4ee6a4SAndroid Build Coastguard Worker     if track_dirty_pages {
456*bb4ee6a4SAndroid Build Coastguard Worker         flags |= WHV_MAP_GPA_RANGE_FLAGS_WHvMapGpaRangeFlagTrackDirtyPages;
457*bb4ee6a4SAndroid Build Coastguard Worker     }
458*bb4ee6a4SAndroid Build Coastguard Worker 
459*bb4ee6a4SAndroid Build Coastguard Worker     let ret = WHvMapGpaRange(
460*bb4ee6a4SAndroid Build Coastguard Worker         partition.partition,
461*bb4ee6a4SAndroid Build Coastguard Worker         userspace_addr as *mut c_void,
462*bb4ee6a4SAndroid Build Coastguard Worker         guest_addr,
463*bb4ee6a4SAndroid Build Coastguard Worker         memory_size,
464*bb4ee6a4SAndroid Build Coastguard Worker         flags,
465*bb4ee6a4SAndroid Build Coastguard Worker     );
466*bb4ee6a4SAndroid Build Coastguard Worker     check_whpx!(ret)
467*bb4ee6a4SAndroid Build Coastguard Worker }
468*bb4ee6a4SAndroid Build Coastguard Worker 
469*bb4ee6a4SAndroid Build Coastguard Worker /// Helper function to determine the size in bytes of a dirty log bitmap for the given memory region
470*bb4ee6a4SAndroid Build Coastguard Worker /// size.
471*bb4ee6a4SAndroid Build Coastguard Worker ///
472*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
473*bb4ee6a4SAndroid Build Coastguard Worker ///
474*bb4ee6a4SAndroid Build Coastguard Worker /// * `size` - Number of bytes in the memory region being queried.
dirty_log_bitmap_size(size: usize) -> usize475*bb4ee6a4SAndroid Build Coastguard Worker pub fn dirty_log_bitmap_size(size: usize) -> usize {
476*bb4ee6a4SAndroid Build Coastguard Worker     let page_size = pagesize();
477*bb4ee6a4SAndroid Build Coastguard Worker     (((size + page_size - 1) / page_size) + 7) / 8
478*bb4ee6a4SAndroid Build Coastguard Worker }
479*bb4ee6a4SAndroid Build Coastguard Worker 
480*bb4ee6a4SAndroid Build Coastguard Worker impl Vm for WhpxVm {
481*bb4ee6a4SAndroid Build Coastguard Worker     /// Makes a shallow clone of this `Vm`.
try_clone(&self) -> Result<Self>482*bb4ee6a4SAndroid Build Coastguard Worker     fn try_clone(&self) -> Result<Self> {
483*bb4ee6a4SAndroid Build Coastguard Worker         let mut ioevents = FnvHashMap::default();
484*bb4ee6a4SAndroid Build Coastguard Worker         for (addr, evt) in self.ioevents.iter() {
485*bb4ee6a4SAndroid Build Coastguard Worker             ioevents.insert(*addr, evt.try_clone()?);
486*bb4ee6a4SAndroid Build Coastguard Worker         }
487*bb4ee6a4SAndroid Build Coastguard Worker         Ok(WhpxVm {
488*bb4ee6a4SAndroid Build Coastguard Worker             whpx: self.whpx.try_clone()?,
489*bb4ee6a4SAndroid Build Coastguard Worker             vm_partition: self.vm_partition.clone(),
490*bb4ee6a4SAndroid Build Coastguard Worker             guest_mem: self.guest_mem.clone(),
491*bb4ee6a4SAndroid Build Coastguard Worker             mem_regions: self.mem_regions.clone(),
492*bb4ee6a4SAndroid Build Coastguard Worker             mem_slot_gaps: self.mem_slot_gaps.clone(),
493*bb4ee6a4SAndroid Build Coastguard Worker             ioevents,
494*bb4ee6a4SAndroid Build Coastguard Worker             vm_evt_wrtube: self
495*bb4ee6a4SAndroid Build Coastguard Worker                 .vm_evt_wrtube
496*bb4ee6a4SAndroid Build Coastguard Worker                 .as_ref()
497*bb4ee6a4SAndroid Build Coastguard Worker                 .map(|t| t.try_clone().expect("could not clone vm_evt_wrtube")),
498*bb4ee6a4SAndroid Build Coastguard Worker         })
499*bb4ee6a4SAndroid Build Coastguard Worker     }
500*bb4ee6a4SAndroid Build Coastguard Worker 
check_capability(&self, c: VmCap) -> bool501*bb4ee6a4SAndroid Build Coastguard Worker     fn check_capability(&self, c: VmCap) -> bool {
502*bb4ee6a4SAndroid Build Coastguard Worker         match c {
503*bb4ee6a4SAndroid Build Coastguard Worker             VmCap::DirtyLog => Whpx::check_whpx_feature(WhpxFeature::DirtyPageTracking)
504*bb4ee6a4SAndroid Build Coastguard Worker                 .unwrap_or_else(|e| {
505*bb4ee6a4SAndroid Build Coastguard Worker                     error!(
506*bb4ee6a4SAndroid Build Coastguard Worker                         "failed to check whpx feature {:?}: {}",
507*bb4ee6a4SAndroid Build Coastguard Worker                         WhpxFeature::DirtyPageTracking,
508*bb4ee6a4SAndroid Build Coastguard Worker                         e
509*bb4ee6a4SAndroid Build Coastguard Worker                     );
510*bb4ee6a4SAndroid Build Coastguard Worker                     false
511*bb4ee6a4SAndroid Build Coastguard Worker                 }),
512*bb4ee6a4SAndroid Build Coastguard Worker             // there is a pvclock like thing already done w/ hyperv, but we can't get the state.
513*bb4ee6a4SAndroid Build Coastguard Worker             VmCap::PvClock => false,
514*bb4ee6a4SAndroid Build Coastguard Worker             VmCap::Protected => false,
515*bb4ee6a4SAndroid Build Coastguard Worker             // whpx initializes cpuid early during VM creation.
516*bb4ee6a4SAndroid Build Coastguard Worker             VmCap::EarlyInitCpuid => true,
517*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(target_arch = "x86_64")]
518*bb4ee6a4SAndroid Build Coastguard Worker             VmCap::BusLockDetect => false,
519*bb4ee6a4SAndroid Build Coastguard Worker             VmCap::ReadOnlyMemoryRegion => true,
520*bb4ee6a4SAndroid Build Coastguard Worker             VmCap::MemNoncoherentDma => false,
521*bb4ee6a4SAndroid Build Coastguard Worker         }
522*bb4ee6a4SAndroid Build Coastguard Worker     }
523*bb4ee6a4SAndroid Build Coastguard Worker 
get_memory(&self) -> &GuestMemory524*bb4ee6a4SAndroid Build Coastguard Worker     fn get_memory(&self) -> &GuestMemory {
525*bb4ee6a4SAndroid Build Coastguard Worker         &self.guest_mem
526*bb4ee6a4SAndroid Build Coastguard Worker     }
527*bb4ee6a4SAndroid Build Coastguard Worker 
add_memory_region( &mut self, guest_addr: GuestAddress, mem: Box<dyn MappedRegion>, read_only: bool, log_dirty_pages: bool, _cache: MemCacheType, ) -> Result<MemSlot>528*bb4ee6a4SAndroid Build Coastguard Worker     fn add_memory_region(
529*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
530*bb4ee6a4SAndroid Build Coastguard Worker         guest_addr: GuestAddress,
531*bb4ee6a4SAndroid Build Coastguard Worker         mem: Box<dyn MappedRegion>,
532*bb4ee6a4SAndroid Build Coastguard Worker         read_only: bool,
533*bb4ee6a4SAndroid Build Coastguard Worker         log_dirty_pages: bool,
534*bb4ee6a4SAndroid Build Coastguard Worker         _cache: MemCacheType,
535*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<MemSlot> {
536*bb4ee6a4SAndroid Build Coastguard Worker         let size = mem.size() as u64;
537*bb4ee6a4SAndroid Build Coastguard Worker         let end_addr = guest_addr.checked_add(size).ok_or(Error::new(EOVERFLOW))?;
538*bb4ee6a4SAndroid Build Coastguard Worker         if self.guest_mem.range_overlap(guest_addr, end_addr) {
539*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::new(ENOSPC));
540*bb4ee6a4SAndroid Build Coastguard Worker         }
541*bb4ee6a4SAndroid Build Coastguard Worker         let mut regions = self.mem_regions.lock();
542*bb4ee6a4SAndroid Build Coastguard Worker         let mut gaps = self.mem_slot_gaps.lock();
543*bb4ee6a4SAndroid Build Coastguard Worker         let slot = match gaps.pop() {
544*bb4ee6a4SAndroid Build Coastguard Worker             Some(gap) => gap.0,
545*bb4ee6a4SAndroid Build Coastguard Worker             None => (regions.len() + self.guest_mem.num_regions() as usize) as MemSlot,
546*bb4ee6a4SAndroid Build Coastguard Worker         };
547*bb4ee6a4SAndroid Build Coastguard Worker 
548*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because we check that the given guest address is valid and has no overlaps. We also
549*bb4ee6a4SAndroid Build Coastguard Worker         // know that the pointer and size are correct because the MemoryMapping interface ensures
550*bb4ee6a4SAndroid Build Coastguard Worker         // this. We take ownership of the memory mapping so that it won't be unmapped until the slot
551*bb4ee6a4SAndroid Build Coastguard Worker         // is removed.
552*bb4ee6a4SAndroid Build Coastguard Worker         let res = unsafe {
553*bb4ee6a4SAndroid Build Coastguard Worker             set_user_memory_region(
554*bb4ee6a4SAndroid Build Coastguard Worker                 &self.vm_partition,
555*bb4ee6a4SAndroid Build Coastguard Worker                 read_only,
556*bb4ee6a4SAndroid Build Coastguard Worker                 log_dirty_pages,
557*bb4ee6a4SAndroid Build Coastguard Worker                 guest_addr.offset(),
558*bb4ee6a4SAndroid Build Coastguard Worker                 size,
559*bb4ee6a4SAndroid Build Coastguard Worker                 mem.as_ptr(),
560*bb4ee6a4SAndroid Build Coastguard Worker             )
561*bb4ee6a4SAndroid Build Coastguard Worker         };
562*bb4ee6a4SAndroid Build Coastguard Worker 
563*bb4ee6a4SAndroid Build Coastguard Worker         if let Err(e) = res {
564*bb4ee6a4SAndroid Build Coastguard Worker             gaps.push(Reverse(slot));
565*bb4ee6a4SAndroid Build Coastguard Worker             return Err(e);
566*bb4ee6a4SAndroid Build Coastguard Worker         }
567*bb4ee6a4SAndroid Build Coastguard Worker         regions.insert(slot, (guest_addr, mem));
568*bb4ee6a4SAndroid Build Coastguard Worker         Ok(slot)
569*bb4ee6a4SAndroid Build Coastguard Worker     }
570*bb4ee6a4SAndroid Build Coastguard Worker 
msync_memory_region(&mut self, slot: MemSlot, offset: usize, size: usize) -> Result<()>571*bb4ee6a4SAndroid Build Coastguard Worker     fn msync_memory_region(&mut self, slot: MemSlot, offset: usize, size: usize) -> Result<()> {
572*bb4ee6a4SAndroid Build Coastguard Worker         let mut regions = self.mem_regions.lock();
573*bb4ee6a4SAndroid Build Coastguard Worker         let (_, mem) = regions.get_mut(&slot).ok_or(Error::new(ENOENT))?;
574*bb4ee6a4SAndroid Build Coastguard Worker 
575*bb4ee6a4SAndroid Build Coastguard Worker         mem.msync(offset, size).map_err(|err| match err {
576*bb4ee6a4SAndroid Build Coastguard Worker             MmapError::InvalidAddress => Error::new(EFAULT),
577*bb4ee6a4SAndroid Build Coastguard Worker             MmapError::NotPageAligned => Error::new(EINVAL),
578*bb4ee6a4SAndroid Build Coastguard Worker             MmapError::SystemCallFailed(e) => e,
579*bb4ee6a4SAndroid Build Coastguard Worker             _ => Error::new(EIO),
580*bb4ee6a4SAndroid Build Coastguard Worker         })
581*bb4ee6a4SAndroid Build Coastguard Worker     }
582*bb4ee6a4SAndroid Build Coastguard Worker 
remove_memory_region(&mut self, slot: MemSlot) -> Result<Box<dyn MappedRegion>>583*bb4ee6a4SAndroid Build Coastguard Worker     fn remove_memory_region(&mut self, slot: MemSlot) -> Result<Box<dyn MappedRegion>> {
584*bb4ee6a4SAndroid Build Coastguard Worker         let mut regions = self.mem_regions.lock();
585*bb4ee6a4SAndroid Build Coastguard Worker         if !regions.contains_key(&slot) {
586*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::new(ENOENT));
587*bb4ee6a4SAndroid Build Coastguard Worker         }
588*bb4ee6a4SAndroid Build Coastguard Worker         if let Some((guest_addr, mem)) = regions.get(&slot) {
589*bb4ee6a4SAndroid Build Coastguard Worker             // Safe because the slot is checked against the list of memory slots.
590*bb4ee6a4SAndroid Build Coastguard Worker             unsafe {
591*bb4ee6a4SAndroid Build Coastguard Worker                 check_whpx!(WHvUnmapGpaRange(
592*bb4ee6a4SAndroid Build Coastguard Worker                     self.vm_partition.partition,
593*bb4ee6a4SAndroid Build Coastguard Worker                     guest_addr.offset(),
594*bb4ee6a4SAndroid Build Coastguard Worker                     mem.size() as u64,
595*bb4ee6a4SAndroid Build Coastguard Worker                 ))?;
596*bb4ee6a4SAndroid Build Coastguard Worker             }
597*bb4ee6a4SAndroid Build Coastguard Worker             self.mem_slot_gaps.lock().push(Reverse(slot));
598*bb4ee6a4SAndroid Build Coastguard Worker             Ok(regions.remove(&slot).unwrap().1)
599*bb4ee6a4SAndroid Build Coastguard Worker         } else {
600*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::new(ENOENT))
601*bb4ee6a4SAndroid Build Coastguard Worker         }
602*bb4ee6a4SAndroid Build Coastguard Worker     }
603*bb4ee6a4SAndroid Build Coastguard Worker 
create_device(&self, _kind: DeviceKind) -> Result<SafeDescriptor>604*bb4ee6a4SAndroid Build Coastguard Worker     fn create_device(&self, _kind: DeviceKind) -> Result<SafeDescriptor> {
605*bb4ee6a4SAndroid Build Coastguard Worker         // Whpx does not support in-kernel devices
606*bb4ee6a4SAndroid Build Coastguard Worker         Err(Error::new(libc::ENXIO))
607*bb4ee6a4SAndroid Build Coastguard Worker     }
608*bb4ee6a4SAndroid Build Coastguard Worker 
get_dirty_log(&self, slot: u32, dirty_log: &mut [u8]) -> Result<()>609*bb4ee6a4SAndroid Build Coastguard Worker     fn get_dirty_log(&self, slot: u32, dirty_log: &mut [u8]) -> Result<()> {
610*bb4ee6a4SAndroid Build Coastguard Worker         let regions = self.mem_regions.lock();
611*bb4ee6a4SAndroid Build Coastguard Worker         if let Some((guest_addr, mem)) = regions.get(&slot) {
612*bb4ee6a4SAndroid Build Coastguard Worker             // Ensures that there are as many bytes in dirty_log as there are pages in the mmap.
613*bb4ee6a4SAndroid Build Coastguard Worker             if dirty_log_bitmap_size(mem.size()) > dirty_log.len() {
614*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(Error::new(EINVAL));
615*bb4ee6a4SAndroid Build Coastguard Worker             }
616*bb4ee6a4SAndroid Build Coastguard Worker             let bitmap_size = if dirty_log.len() % 8 == 0 {
617*bb4ee6a4SAndroid Build Coastguard Worker                 dirty_log.len() / 8
618*bb4ee6a4SAndroid Build Coastguard Worker             } else {
619*bb4ee6a4SAndroid Build Coastguard Worker                 dirty_log.len() / 8 + 1
620*bb4ee6a4SAndroid Build Coastguard Worker             };
621*bb4ee6a4SAndroid Build Coastguard Worker             let mut bitmap = vec![0u64; bitmap_size];
622*bb4ee6a4SAndroid Build Coastguard Worker             check_whpx!(unsafe {
623*bb4ee6a4SAndroid Build Coastguard Worker                 WHvQueryGpaRangeDirtyBitmap(
624*bb4ee6a4SAndroid Build Coastguard Worker                     self.vm_partition.partition,
625*bb4ee6a4SAndroid Build Coastguard Worker                     guest_addr.offset(),
626*bb4ee6a4SAndroid Build Coastguard Worker                     mem.size() as u64,
627*bb4ee6a4SAndroid Build Coastguard Worker                     bitmap.as_mut_ptr() as *mut u64,
628*bb4ee6a4SAndroid Build Coastguard Worker                     (bitmap.len() * 8) as u32,
629*bb4ee6a4SAndroid Build Coastguard Worker                 )
630*bb4ee6a4SAndroid Build Coastguard Worker             })?;
631*bb4ee6a4SAndroid Build Coastguard Worker             // safe because we have allocated a vec of u64, which we can cast to a u8 slice.
632*bb4ee6a4SAndroid Build Coastguard Worker             let buffer = unsafe {
633*bb4ee6a4SAndroid Build Coastguard Worker                 std::slice::from_raw_parts(bitmap.as_ptr() as *const u8, bitmap.len() * 8)
634*bb4ee6a4SAndroid Build Coastguard Worker             };
635*bb4ee6a4SAndroid Build Coastguard Worker             dirty_log.copy_from_slice(&buffer[..dirty_log.len()]);
636*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
637*bb4ee6a4SAndroid Build Coastguard Worker         } else {
638*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::new(ENOENT))
639*bb4ee6a4SAndroid Build Coastguard Worker         }
640*bb4ee6a4SAndroid Build Coastguard Worker     }
641*bb4ee6a4SAndroid Build Coastguard Worker 
register_ioevent( &mut self, evt: &Event, addr: IoEventAddress, datamatch: Datamatch, ) -> Result<()>642*bb4ee6a4SAndroid Build Coastguard Worker     fn register_ioevent(
643*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
644*bb4ee6a4SAndroid Build Coastguard Worker         evt: &Event,
645*bb4ee6a4SAndroid Build Coastguard Worker         addr: IoEventAddress,
646*bb4ee6a4SAndroid Build Coastguard Worker         datamatch: Datamatch,
647*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
648*bb4ee6a4SAndroid Build Coastguard Worker         if datamatch != Datamatch::AnyLength {
649*bb4ee6a4SAndroid Build Coastguard Worker             error!("WHPX currently only supports Datamatch::AnyLength");
650*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::new(ENOTSUP));
651*bb4ee6a4SAndroid Build Coastguard Worker         }
652*bb4ee6a4SAndroid Build Coastguard Worker 
653*bb4ee6a4SAndroid Build Coastguard Worker         if self.ioevents.contains_key(&addr) {
654*bb4ee6a4SAndroid Build Coastguard Worker             error!("WHPX does not support multiple ioevents for the same address");
655*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::new(EEXIST));
656*bb4ee6a4SAndroid Build Coastguard Worker         }
657*bb4ee6a4SAndroid Build Coastguard Worker 
658*bb4ee6a4SAndroid Build Coastguard Worker         self.ioevents.insert(addr, evt.try_clone()?);
659*bb4ee6a4SAndroid Build Coastguard Worker 
660*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
661*bb4ee6a4SAndroid Build Coastguard Worker     }
662*bb4ee6a4SAndroid Build Coastguard Worker 
unregister_ioevent( &mut self, evt: &Event, addr: IoEventAddress, datamatch: Datamatch, ) -> Result<()>663*bb4ee6a4SAndroid Build Coastguard Worker     fn unregister_ioevent(
664*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
665*bb4ee6a4SAndroid Build Coastguard Worker         evt: &Event,
666*bb4ee6a4SAndroid Build Coastguard Worker         addr: IoEventAddress,
667*bb4ee6a4SAndroid Build Coastguard Worker         datamatch: Datamatch,
668*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
669*bb4ee6a4SAndroid Build Coastguard Worker         if datamatch != Datamatch::AnyLength {
670*bb4ee6a4SAndroid Build Coastguard Worker             error!("WHPX only supports Datamatch::AnyLength");
671*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::new(ENOTSUP));
672*bb4ee6a4SAndroid Build Coastguard Worker         }
673*bb4ee6a4SAndroid Build Coastguard Worker 
674*bb4ee6a4SAndroid Build Coastguard Worker         match self.ioevents.get(&addr) {
675*bb4ee6a4SAndroid Build Coastguard Worker             Some(existing_evt) => {
676*bb4ee6a4SAndroid Build Coastguard Worker                 // evt should match the existing evt associated with addr
677*bb4ee6a4SAndroid Build Coastguard Worker                 if evt != existing_evt {
678*bb4ee6a4SAndroid Build Coastguard Worker                     return Err(Error::new(ENOENT));
679*bb4ee6a4SAndroid Build Coastguard Worker                 }
680*bb4ee6a4SAndroid Build Coastguard Worker                 self.ioevents.remove(&addr);
681*bb4ee6a4SAndroid Build Coastguard Worker             }
682*bb4ee6a4SAndroid Build Coastguard Worker 
683*bb4ee6a4SAndroid Build Coastguard Worker             None => {
684*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(Error::new(ENOENT));
685*bb4ee6a4SAndroid Build Coastguard Worker             }
686*bb4ee6a4SAndroid Build Coastguard Worker         };
687*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
688*bb4ee6a4SAndroid Build Coastguard Worker     }
689*bb4ee6a4SAndroid Build Coastguard Worker 
690*bb4ee6a4SAndroid Build Coastguard Worker     /// Trigger any io events based on the memory mapped IO at `addr`.  If the hypervisor does
691*bb4ee6a4SAndroid Build Coastguard Worker     /// in-kernel IO event delivery, this is a no-op.
handle_io_events(&self, addr: IoEventAddress, _data: &[u8]) -> Result<()>692*bb4ee6a4SAndroid Build Coastguard Worker     fn handle_io_events(&self, addr: IoEventAddress, _data: &[u8]) -> Result<()> {
693*bb4ee6a4SAndroid Build Coastguard Worker         match self.ioevents.get(&addr) {
694*bb4ee6a4SAndroid Build Coastguard Worker             None => {}
695*bb4ee6a4SAndroid Build Coastguard Worker             Some(evt) => {
696*bb4ee6a4SAndroid Build Coastguard Worker                 evt.signal()?;
697*bb4ee6a4SAndroid Build Coastguard Worker             }
698*bb4ee6a4SAndroid Build Coastguard Worker         };
699*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
700*bb4ee6a4SAndroid Build Coastguard Worker     }
701*bb4ee6a4SAndroid Build Coastguard Worker 
get_pvclock(&self) -> Result<ClockState>702*bb4ee6a4SAndroid Build Coastguard Worker     fn get_pvclock(&self) -> Result<ClockState> {
703*bb4ee6a4SAndroid Build Coastguard Worker         Err(Error::new(ENODEV))
704*bb4ee6a4SAndroid Build Coastguard Worker     }
705*bb4ee6a4SAndroid Build Coastguard Worker 
set_pvclock(&self, _state: &ClockState) -> Result<()>706*bb4ee6a4SAndroid Build Coastguard Worker     fn set_pvclock(&self, _state: &ClockState) -> Result<()> {
707*bb4ee6a4SAndroid Build Coastguard Worker         Err(Error::new(ENODEV))
708*bb4ee6a4SAndroid Build Coastguard Worker     }
709*bb4ee6a4SAndroid Build Coastguard Worker 
add_fd_mapping( &mut self, slot: u32, offset: usize, size: usize, fd: &dyn AsRawDescriptor, fd_offset: u64, prot: Protection, ) -> Result<()>710*bb4ee6a4SAndroid Build Coastguard Worker     fn add_fd_mapping(
711*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
712*bb4ee6a4SAndroid Build Coastguard Worker         slot: u32,
713*bb4ee6a4SAndroid Build Coastguard Worker         offset: usize,
714*bb4ee6a4SAndroid Build Coastguard Worker         size: usize,
715*bb4ee6a4SAndroid Build Coastguard Worker         fd: &dyn AsRawDescriptor,
716*bb4ee6a4SAndroid Build Coastguard Worker         fd_offset: u64,
717*bb4ee6a4SAndroid Build Coastguard Worker         prot: Protection,
718*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
719*bb4ee6a4SAndroid Build Coastguard Worker         let mut regions = self.mem_regions.lock();
720*bb4ee6a4SAndroid Build Coastguard Worker         let (_, region) = regions.get_mut(&slot).ok_or(Error::new(EINVAL))?;
721*bb4ee6a4SAndroid Build Coastguard Worker 
722*bb4ee6a4SAndroid Build Coastguard Worker         match region.add_fd_mapping(offset, size, fd, fd_offset, prot) {
723*bb4ee6a4SAndroid Build Coastguard Worker             Ok(()) => Ok(()),
724*bb4ee6a4SAndroid Build Coastguard Worker             Err(MmapError::SystemCallFailed(e)) => Err(e),
725*bb4ee6a4SAndroid Build Coastguard Worker             Err(_) => Err(Error::new(EIO)),
726*bb4ee6a4SAndroid Build Coastguard Worker         }
727*bb4ee6a4SAndroid Build Coastguard Worker     }
728*bb4ee6a4SAndroid Build Coastguard Worker 
remove_mapping(&mut self, slot: u32, offset: usize, size: usize) -> Result<()>729*bb4ee6a4SAndroid Build Coastguard Worker     fn remove_mapping(&mut self, slot: u32, offset: usize, size: usize) -> Result<()> {
730*bb4ee6a4SAndroid Build Coastguard Worker         let mut regions = self.mem_regions.lock();
731*bb4ee6a4SAndroid Build Coastguard Worker         let (_, region) = regions.get_mut(&slot).ok_or(Error::new(EINVAL))?;
732*bb4ee6a4SAndroid Build Coastguard Worker 
733*bb4ee6a4SAndroid Build Coastguard Worker         match region.remove_mapping(offset, size) {
734*bb4ee6a4SAndroid Build Coastguard Worker             Ok(()) => Ok(()),
735*bb4ee6a4SAndroid Build Coastguard Worker             Err(MmapError::SystemCallFailed(e)) => Err(e),
736*bb4ee6a4SAndroid Build Coastguard Worker             Err(_) => Err(Error::new(EIO)),
737*bb4ee6a4SAndroid Build Coastguard Worker         }
738*bb4ee6a4SAndroid Build Coastguard Worker     }
739*bb4ee6a4SAndroid Build Coastguard Worker 
handle_balloon_event(&mut self, event: BalloonEvent) -> Result<()>740*bb4ee6a4SAndroid Build Coastguard Worker     fn handle_balloon_event(&mut self, event: BalloonEvent) -> Result<()> {
741*bb4ee6a4SAndroid Build Coastguard Worker         match event {
742*bb4ee6a4SAndroid Build Coastguard Worker             BalloonEvent::Inflate(m) => self.handle_inflate(m.guest_address, m.size),
743*bb4ee6a4SAndroid Build Coastguard Worker             BalloonEvent::Deflate(m) => self.handle_deflate(m.guest_address, m.size),
744*bb4ee6a4SAndroid Build Coastguard Worker             BalloonEvent::BalloonTargetReached(_) => Ok(()),
745*bb4ee6a4SAndroid Build Coastguard Worker         }
746*bb4ee6a4SAndroid Build Coastguard Worker     }
747*bb4ee6a4SAndroid Build Coastguard Worker 
get_guest_phys_addr_bits(&self) -> u8748*bb4ee6a4SAndroid Build Coastguard Worker     fn get_guest_phys_addr_bits(&self) -> u8 {
749*bb4ee6a4SAndroid Build Coastguard Worker         // Assume the guest physical address size is the same as the host.
750*bb4ee6a4SAndroid Build Coastguard Worker         host_phys_addr_bits()
751*bb4ee6a4SAndroid Build Coastguard Worker     }
752*bb4ee6a4SAndroid Build Coastguard Worker }
753*bb4ee6a4SAndroid Build Coastguard Worker 
754*bb4ee6a4SAndroid Build Coastguard Worker impl VmX86_64 for WhpxVm {
get_hypervisor(&self) -> &dyn HypervisorX86_64755*bb4ee6a4SAndroid Build Coastguard Worker     fn get_hypervisor(&self) -> &dyn HypervisorX86_64 {
756*bb4ee6a4SAndroid Build Coastguard Worker         &self.whpx
757*bb4ee6a4SAndroid Build Coastguard Worker     }
758*bb4ee6a4SAndroid Build Coastguard Worker 
create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuX86_64>>759*bb4ee6a4SAndroid Build Coastguard Worker     fn create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuX86_64>> {
760*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Box::new(WhpxVcpu::new(
761*bb4ee6a4SAndroid Build Coastguard Worker             self.vm_partition.clone(),
762*bb4ee6a4SAndroid Build Coastguard Worker             id.try_into().unwrap(),
763*bb4ee6a4SAndroid Build Coastguard Worker         )?))
764*bb4ee6a4SAndroid Build Coastguard Worker     }
765*bb4ee6a4SAndroid Build Coastguard Worker 
766*bb4ee6a4SAndroid Build Coastguard Worker     /// Sets the address of the three-page region in the VM's address space.
767*bb4ee6a4SAndroid Build Coastguard Worker     /// This function is only necessary for unrestricted_guest_mode=0, which we do not support for
768*bb4ee6a4SAndroid Build Coastguard Worker     /// WHPX.
set_tss_addr(&self, _addr: GuestAddress) -> Result<()>769*bb4ee6a4SAndroid Build Coastguard Worker     fn set_tss_addr(&self, _addr: GuestAddress) -> Result<()> {
770*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
771*bb4ee6a4SAndroid Build Coastguard Worker     }
772*bb4ee6a4SAndroid Build Coastguard Worker 
773*bb4ee6a4SAndroid Build Coastguard Worker     /// Sets the address of a one-page region in the VM's address space.
774*bb4ee6a4SAndroid Build Coastguard Worker     /// This function is only necessary for unrestricted_guest_mode=0, which we do not support for
775*bb4ee6a4SAndroid Build Coastguard Worker     /// WHPX.
set_identity_map_addr(&self, _addr: GuestAddress) -> Result<()>776*bb4ee6a4SAndroid Build Coastguard Worker     fn set_identity_map_addr(&self, _addr: GuestAddress) -> Result<()> {
777*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
778*bb4ee6a4SAndroid Build Coastguard Worker     }
779*bb4ee6a4SAndroid Build Coastguard Worker }
780*bb4ee6a4SAndroid Build Coastguard Worker 
781*bb4ee6a4SAndroid Build Coastguard Worker // NOTE: WHPX Tests need to be run serially as otherwise it barfs unless we map new regions of guest
782*bb4ee6a4SAndroid Build Coastguard Worker // memory.
783*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
784*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
785*bb4ee6a4SAndroid Build Coastguard Worker     use std::thread;
786*bb4ee6a4SAndroid Build Coastguard Worker     use std::time::Duration;
787*bb4ee6a4SAndroid Build Coastguard Worker 
788*bb4ee6a4SAndroid Build Coastguard Worker     use base::EventWaitResult;
789*bb4ee6a4SAndroid Build Coastguard Worker     use base::MemoryMappingBuilder;
790*bb4ee6a4SAndroid Build Coastguard Worker     use base::SharedMemory;
791*bb4ee6a4SAndroid Build Coastguard Worker 
792*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
793*bb4ee6a4SAndroid Build Coastguard Worker 
new_vm(cpu_count: usize, mem: GuestMemory) -> WhpxVm794*bb4ee6a4SAndroid Build Coastguard Worker     fn new_vm(cpu_count: usize, mem: GuestMemory) -> WhpxVm {
795*bb4ee6a4SAndroid Build Coastguard Worker         let whpx = Whpx::new().expect("failed to instantiate whpx");
796*bb4ee6a4SAndroid Build Coastguard Worker         let local_apic_supported = Whpx::check_whpx_feature(WhpxFeature::LocalApicEmulation)
797*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to get whpx features");
798*bb4ee6a4SAndroid Build Coastguard Worker         WhpxVm::new(
799*bb4ee6a4SAndroid Build Coastguard Worker             &whpx,
800*bb4ee6a4SAndroid Build Coastguard Worker             cpu_count,
801*bb4ee6a4SAndroid Build Coastguard Worker             mem,
802*bb4ee6a4SAndroid Build Coastguard Worker             CpuId::new(0),
803*bb4ee6a4SAndroid Build Coastguard Worker             local_apic_supported,
804*bb4ee6a4SAndroid Build Coastguard Worker             None,
805*bb4ee6a4SAndroid Build Coastguard Worker         )
806*bb4ee6a4SAndroid Build Coastguard Worker         .expect("failed to create whpx vm")
807*bb4ee6a4SAndroid Build Coastguard Worker     }
808*bb4ee6a4SAndroid Build Coastguard Worker 
809*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
create_vm()810*bb4ee6a4SAndroid Build Coastguard Worker     fn create_vm() {
811*bb4ee6a4SAndroid Build Coastguard Worker         if !Whpx::is_enabled() {
812*bb4ee6a4SAndroid Build Coastguard Worker             return;
813*bb4ee6a4SAndroid Build Coastguard Worker         }
814*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_count = 1;
815*bb4ee6a4SAndroid Build Coastguard Worker         let mem =
816*bb4ee6a4SAndroid Build Coastguard Worker             GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory");
817*bb4ee6a4SAndroid Build Coastguard Worker         new_vm(cpu_count, mem);
818*bb4ee6a4SAndroid Build Coastguard Worker     }
819*bb4ee6a4SAndroid Build Coastguard Worker 
820*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
create_vcpu()821*bb4ee6a4SAndroid Build Coastguard Worker     fn create_vcpu() {
822*bb4ee6a4SAndroid Build Coastguard Worker         if !Whpx::is_enabled() {
823*bb4ee6a4SAndroid Build Coastguard Worker             return;
824*bb4ee6a4SAndroid Build Coastguard Worker         }
825*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_count = 1;
826*bb4ee6a4SAndroid Build Coastguard Worker         let mem =
827*bb4ee6a4SAndroid Build Coastguard Worker             GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory");
828*bb4ee6a4SAndroid Build Coastguard Worker         let vm = new_vm(cpu_count, mem);
829*bb4ee6a4SAndroid Build Coastguard Worker         vm.create_vcpu(0).expect("failed to create vcpu");
830*bb4ee6a4SAndroid Build Coastguard Worker     }
831*bb4ee6a4SAndroid Build Coastguard Worker 
832*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
try_clone()833*bb4ee6a4SAndroid Build Coastguard Worker     fn try_clone() {
834*bb4ee6a4SAndroid Build Coastguard Worker         if !Whpx::is_enabled() {
835*bb4ee6a4SAndroid Build Coastguard Worker             return;
836*bb4ee6a4SAndroid Build Coastguard Worker         }
837*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_count = 1;
838*bb4ee6a4SAndroid Build Coastguard Worker         let mem =
839*bb4ee6a4SAndroid Build Coastguard Worker             GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory");
840*bb4ee6a4SAndroid Build Coastguard Worker         let vm = new_vm(cpu_count, mem);
841*bb4ee6a4SAndroid Build Coastguard Worker         let _vm_clone = vm.try_clone().expect("failed to clone whpx vm");
842*bb4ee6a4SAndroid Build Coastguard Worker     }
843*bb4ee6a4SAndroid Build Coastguard Worker 
844*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
send_vm()845*bb4ee6a4SAndroid Build Coastguard Worker     fn send_vm() {
846*bb4ee6a4SAndroid Build Coastguard Worker         if !Whpx::is_enabled() {
847*bb4ee6a4SAndroid Build Coastguard Worker             return;
848*bb4ee6a4SAndroid Build Coastguard Worker         }
849*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_count = 1;
850*bb4ee6a4SAndroid Build Coastguard Worker         let mem =
851*bb4ee6a4SAndroid Build Coastguard Worker             GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory");
852*bb4ee6a4SAndroid Build Coastguard Worker         let vm = new_vm(cpu_count, mem);
853*bb4ee6a4SAndroid Build Coastguard Worker         thread::spawn(move || {
854*bb4ee6a4SAndroid Build Coastguard Worker             let _vm = vm;
855*bb4ee6a4SAndroid Build Coastguard Worker         })
856*bb4ee6a4SAndroid Build Coastguard Worker         .join()
857*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
858*bb4ee6a4SAndroid Build Coastguard Worker     }
859*bb4ee6a4SAndroid Build Coastguard Worker 
860*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
check_vm_capability()861*bb4ee6a4SAndroid Build Coastguard Worker     fn check_vm_capability() {
862*bb4ee6a4SAndroid Build Coastguard Worker         if !Whpx::is_enabled() {
863*bb4ee6a4SAndroid Build Coastguard Worker             return;
864*bb4ee6a4SAndroid Build Coastguard Worker         }
865*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_count = 1;
866*bb4ee6a4SAndroid Build Coastguard Worker         let mem =
867*bb4ee6a4SAndroid Build Coastguard Worker             GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory");
868*bb4ee6a4SAndroid Build Coastguard Worker         let vm = new_vm(cpu_count, mem);
869*bb4ee6a4SAndroid Build Coastguard Worker         assert!(vm.check_capability(VmCap::DirtyLog));
870*bb4ee6a4SAndroid Build Coastguard Worker         assert!(!vm.check_capability(VmCap::PvClock));
871*bb4ee6a4SAndroid Build Coastguard Worker     }
872*bb4ee6a4SAndroid Build Coastguard Worker 
873*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
dirty_log_size()874*bb4ee6a4SAndroid Build Coastguard Worker     fn dirty_log_size() {
875*bb4ee6a4SAndroid Build Coastguard Worker         let page_size = pagesize();
876*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(dirty_log_bitmap_size(0), 0);
877*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(dirty_log_bitmap_size(page_size), 1);
878*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(dirty_log_bitmap_size(page_size * 8), 1);
879*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(dirty_log_bitmap_size(page_size * 8 + 1), 2);
880*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(dirty_log_bitmap_size(page_size * 100), 13);
881*bb4ee6a4SAndroid Build Coastguard Worker     }
882*bb4ee6a4SAndroid Build Coastguard Worker 
883*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
register_ioevent()884*bb4ee6a4SAndroid Build Coastguard Worker     fn register_ioevent() {
885*bb4ee6a4SAndroid Build Coastguard Worker         if !Whpx::is_enabled() {
886*bb4ee6a4SAndroid Build Coastguard Worker             return;
887*bb4ee6a4SAndroid Build Coastguard Worker         }
888*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_count = 1;
889*bb4ee6a4SAndroid Build Coastguard Worker         let mem =
890*bb4ee6a4SAndroid Build Coastguard Worker             GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory");
891*bb4ee6a4SAndroid Build Coastguard Worker         let mut vm = new_vm(cpu_count, mem);
892*bb4ee6a4SAndroid Build Coastguard Worker         let evt = Event::new().expect("failed to create event");
893*bb4ee6a4SAndroid Build Coastguard Worker         let otherevt = Event::new().expect("failed to create event");
894*bb4ee6a4SAndroid Build Coastguard Worker         vm.register_ioevent(&evt, IoEventAddress::Pio(0xf4), Datamatch::AnyLength)
895*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
896*bb4ee6a4SAndroid Build Coastguard Worker         vm.register_ioevent(&evt, IoEventAddress::Mmio(0x1000), Datamatch::AnyLength)
897*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
898*bb4ee6a4SAndroid Build Coastguard Worker 
899*bb4ee6a4SAndroid Build Coastguard Worker         vm.register_ioevent(
900*bb4ee6a4SAndroid Build Coastguard Worker             &otherevt,
901*bb4ee6a4SAndroid Build Coastguard Worker             IoEventAddress::Mmio(0x1000),
902*bb4ee6a4SAndroid Build Coastguard Worker             Datamatch::AnyLength,
903*bb4ee6a4SAndroid Build Coastguard Worker         )
904*bb4ee6a4SAndroid Build Coastguard Worker         .expect_err("WHPX should not allow you to register two events for the same address");
905*bb4ee6a4SAndroid Build Coastguard Worker 
906*bb4ee6a4SAndroid Build Coastguard Worker         vm.register_ioevent(
907*bb4ee6a4SAndroid Build Coastguard Worker             &otherevt,
908*bb4ee6a4SAndroid Build Coastguard Worker             IoEventAddress::Mmio(0x1000),
909*bb4ee6a4SAndroid Build Coastguard Worker             Datamatch::U8(None),
910*bb4ee6a4SAndroid Build Coastguard Worker         )
911*bb4ee6a4SAndroid Build Coastguard Worker         .expect_err(
912*bb4ee6a4SAndroid Build Coastguard Worker             "WHPX should not allow you to register ioevents with Datamatches other than AnyLength",
913*bb4ee6a4SAndroid Build Coastguard Worker         );
914*bb4ee6a4SAndroid Build Coastguard Worker 
915*bb4ee6a4SAndroid Build Coastguard Worker         vm.register_ioevent(
916*bb4ee6a4SAndroid Build Coastguard Worker             &otherevt,
917*bb4ee6a4SAndroid Build Coastguard Worker             IoEventAddress::Mmio(0x1000),
918*bb4ee6a4SAndroid Build Coastguard Worker             Datamatch::U32(Some(0xf6)),
919*bb4ee6a4SAndroid Build Coastguard Worker         )
920*bb4ee6a4SAndroid Build Coastguard Worker         .expect_err(
921*bb4ee6a4SAndroid Build Coastguard Worker             "WHPX should not allow you to register ioevents with Datamatches other than AnyLength",
922*bb4ee6a4SAndroid Build Coastguard Worker         );
923*bb4ee6a4SAndroid Build Coastguard Worker 
924*bb4ee6a4SAndroid Build Coastguard Worker         vm.unregister_ioevent(&otherevt, IoEventAddress::Pio(0xf4), Datamatch::AnyLength)
925*bb4ee6a4SAndroid Build Coastguard Worker             .expect_err("unregistering an unknown event should fail");
926*bb4ee6a4SAndroid Build Coastguard Worker         vm.unregister_ioevent(&evt, IoEventAddress::Pio(0xf5), Datamatch::AnyLength)
927*bb4ee6a4SAndroid Build Coastguard Worker             .expect_err("unregistering an unknown PIO address should fail");
928*bb4ee6a4SAndroid Build Coastguard Worker         vm.unregister_ioevent(&evt, IoEventAddress::Pio(0x1000), Datamatch::AnyLength)
929*bb4ee6a4SAndroid Build Coastguard Worker             .expect_err("unregistering an unknown PIO address should fail");
930*bb4ee6a4SAndroid Build Coastguard Worker         vm.unregister_ioevent(&evt, IoEventAddress::Mmio(0xf4), Datamatch::AnyLength)
931*bb4ee6a4SAndroid Build Coastguard Worker             .expect_err("unregistering an unknown MMIO address should fail");
932*bb4ee6a4SAndroid Build Coastguard Worker         vm.unregister_ioevent(&evt, IoEventAddress::Pio(0xf4), Datamatch::AnyLength)
933*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
934*bb4ee6a4SAndroid Build Coastguard Worker         vm.unregister_ioevent(&evt, IoEventAddress::Mmio(0x1000), Datamatch::AnyLength)
935*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
936*bb4ee6a4SAndroid Build Coastguard Worker     }
937*bb4ee6a4SAndroid Build Coastguard Worker 
938*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
handle_io_events()939*bb4ee6a4SAndroid Build Coastguard Worker     fn handle_io_events() {
940*bb4ee6a4SAndroid Build Coastguard Worker         if !Whpx::is_enabled() {
941*bb4ee6a4SAndroid Build Coastguard Worker             return;
942*bb4ee6a4SAndroid Build Coastguard Worker         }
943*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_count = 1;
944*bb4ee6a4SAndroid Build Coastguard Worker         let mem =
945*bb4ee6a4SAndroid Build Coastguard Worker             GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory");
946*bb4ee6a4SAndroid Build Coastguard Worker         let mut vm = new_vm(cpu_count, mem);
947*bb4ee6a4SAndroid Build Coastguard Worker         let evt = Event::new().expect("failed to create event");
948*bb4ee6a4SAndroid Build Coastguard Worker         let evt2 = Event::new().expect("failed to create event");
949*bb4ee6a4SAndroid Build Coastguard Worker         vm.register_ioevent(&evt, IoEventAddress::Pio(0x1000), Datamatch::AnyLength)
950*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
951*bb4ee6a4SAndroid Build Coastguard Worker         vm.register_ioevent(&evt2, IoEventAddress::Mmio(0x1000), Datamatch::AnyLength)
952*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
953*bb4ee6a4SAndroid Build Coastguard Worker 
954*bb4ee6a4SAndroid Build Coastguard Worker         // Check a pio address
955*bb4ee6a4SAndroid Build Coastguard Worker         vm.handle_io_events(IoEventAddress::Pio(0x1000), &[])
956*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to handle_io_events");
957*bb4ee6a4SAndroid Build Coastguard Worker         assert_ne!(
958*bb4ee6a4SAndroid Build Coastguard Worker             evt.wait_timeout(Duration::from_millis(10))
959*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("failed to read event"),
960*bb4ee6a4SAndroid Build Coastguard Worker             EventWaitResult::TimedOut
961*bb4ee6a4SAndroid Build Coastguard Worker         );
962*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
963*bb4ee6a4SAndroid Build Coastguard Worker             evt2.wait_timeout(Duration::from_millis(10))
964*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("failed to read event"),
965*bb4ee6a4SAndroid Build Coastguard Worker             EventWaitResult::TimedOut
966*bb4ee6a4SAndroid Build Coastguard Worker         );
967*bb4ee6a4SAndroid Build Coastguard Worker         // Check an mmio address
968*bb4ee6a4SAndroid Build Coastguard Worker         vm.handle_io_events(IoEventAddress::Mmio(0x1000), &[])
969*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to handle_io_events");
970*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
971*bb4ee6a4SAndroid Build Coastguard Worker             evt.wait_timeout(Duration::from_millis(10))
972*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("failed to read event"),
973*bb4ee6a4SAndroid Build Coastguard Worker             EventWaitResult::TimedOut
974*bb4ee6a4SAndroid Build Coastguard Worker         );
975*bb4ee6a4SAndroid Build Coastguard Worker         assert_ne!(
976*bb4ee6a4SAndroid Build Coastguard Worker             evt2.wait_timeout(Duration::from_millis(10))
977*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("failed to read event"),
978*bb4ee6a4SAndroid Build Coastguard Worker             EventWaitResult::TimedOut
979*bb4ee6a4SAndroid Build Coastguard Worker         );
980*bb4ee6a4SAndroid Build Coastguard Worker 
981*bb4ee6a4SAndroid Build Coastguard Worker         // Check an address that does not match any registered ioevents
982*bb4ee6a4SAndroid Build Coastguard Worker         vm.handle_io_events(IoEventAddress::Pio(0x1001), &[])
983*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to handle_io_events");
984*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
985*bb4ee6a4SAndroid Build Coastguard Worker             evt.wait_timeout(Duration::from_millis(10))
986*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("failed to read event"),
987*bb4ee6a4SAndroid Build Coastguard Worker             EventWaitResult::TimedOut
988*bb4ee6a4SAndroid Build Coastguard Worker         );
989*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
990*bb4ee6a4SAndroid Build Coastguard Worker             evt2.wait_timeout(Duration::from_millis(10))
991*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("failed to read event"),
992*bb4ee6a4SAndroid Build Coastguard Worker             EventWaitResult::TimedOut
993*bb4ee6a4SAndroid Build Coastguard Worker         );
994*bb4ee6a4SAndroid Build Coastguard Worker     }
995*bb4ee6a4SAndroid Build Coastguard Worker 
996*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
add_memory_ro()997*bb4ee6a4SAndroid Build Coastguard Worker     fn add_memory_ro() {
998*bb4ee6a4SAndroid Build Coastguard Worker         if !Whpx::is_enabled() {
999*bb4ee6a4SAndroid Build Coastguard Worker             return;
1000*bb4ee6a4SAndroid Build Coastguard Worker         }
1001*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_count = 1;
1002*bb4ee6a4SAndroid Build Coastguard Worker         let mem =
1003*bb4ee6a4SAndroid Build Coastguard Worker             GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory");
1004*bb4ee6a4SAndroid Build Coastguard Worker         let mut vm = new_vm(cpu_count, mem);
1005*bb4ee6a4SAndroid Build Coastguard Worker         let mem_size = 0x1000;
1006*bb4ee6a4SAndroid Build Coastguard Worker         let shm = SharedMemory::new("test", mem_size as u64).unwrap();
1007*bb4ee6a4SAndroid Build Coastguard Worker         let mem = MemoryMappingBuilder::new(mem_size)
1008*bb4ee6a4SAndroid Build Coastguard Worker             .from_shared_memory(&shm)
1009*bb4ee6a4SAndroid Build Coastguard Worker             .build()
1010*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
1011*bb4ee6a4SAndroid Build Coastguard Worker         vm.add_memory_region(
1012*bb4ee6a4SAndroid Build Coastguard Worker             GuestAddress(0x1000),
1013*bb4ee6a4SAndroid Build Coastguard Worker             Box::new(mem),
1014*bb4ee6a4SAndroid Build Coastguard Worker             true,
1015*bb4ee6a4SAndroid Build Coastguard Worker             false,
1016*bb4ee6a4SAndroid Build Coastguard Worker             MemCacheType::CacheCoherent,
1017*bb4ee6a4SAndroid Build Coastguard Worker         )
1018*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
1019*bb4ee6a4SAndroid Build Coastguard Worker     }
1020*bb4ee6a4SAndroid Build Coastguard Worker 
1021*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
remove_memory()1022*bb4ee6a4SAndroid Build Coastguard Worker     fn remove_memory() {
1023*bb4ee6a4SAndroid Build Coastguard Worker         if !Whpx::is_enabled() {
1024*bb4ee6a4SAndroid Build Coastguard Worker             return;
1025*bb4ee6a4SAndroid Build Coastguard Worker         }
1026*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_count = 1;
1027*bb4ee6a4SAndroid Build Coastguard Worker         let mem =
1028*bb4ee6a4SAndroid Build Coastguard Worker             GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory");
1029*bb4ee6a4SAndroid Build Coastguard Worker         let mut vm = new_vm(cpu_count, mem);
1030*bb4ee6a4SAndroid Build Coastguard Worker         let mem_size = 0x1000;
1031*bb4ee6a4SAndroid Build Coastguard Worker         let shm = SharedMemory::new("test", mem_size as u64).unwrap();
1032*bb4ee6a4SAndroid Build Coastguard Worker         let mem = MemoryMappingBuilder::new(mem_size)
1033*bb4ee6a4SAndroid Build Coastguard Worker             .from_shared_memory(&shm)
1034*bb4ee6a4SAndroid Build Coastguard Worker             .build()
1035*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
1036*bb4ee6a4SAndroid Build Coastguard Worker         let mem_ptr = mem.as_ptr();
1037*bb4ee6a4SAndroid Build Coastguard Worker         let slot = vm
1038*bb4ee6a4SAndroid Build Coastguard Worker             .add_memory_region(
1039*bb4ee6a4SAndroid Build Coastguard Worker                 GuestAddress(0x1000),
1040*bb4ee6a4SAndroid Build Coastguard Worker                 Box::new(mem),
1041*bb4ee6a4SAndroid Build Coastguard Worker                 false,
1042*bb4ee6a4SAndroid Build Coastguard Worker                 false,
1043*bb4ee6a4SAndroid Build Coastguard Worker                 MemCacheType::CacheCoherent,
1044*bb4ee6a4SAndroid Build Coastguard Worker             )
1045*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
1046*bb4ee6a4SAndroid Build Coastguard Worker         let removed_mem = vm.remove_memory_region(slot).unwrap();
1047*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(removed_mem.size(), mem_size);
1048*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(removed_mem.as_ptr(), mem_ptr);
1049*bb4ee6a4SAndroid Build Coastguard Worker     }
1050*bb4ee6a4SAndroid Build Coastguard Worker 
1051*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
remove_invalid_memory()1052*bb4ee6a4SAndroid Build Coastguard Worker     fn remove_invalid_memory() {
1053*bb4ee6a4SAndroid Build Coastguard Worker         if !Whpx::is_enabled() {
1054*bb4ee6a4SAndroid Build Coastguard Worker             return;
1055*bb4ee6a4SAndroid Build Coastguard Worker         }
1056*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_count = 1;
1057*bb4ee6a4SAndroid Build Coastguard Worker         let mem =
1058*bb4ee6a4SAndroid Build Coastguard Worker             GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory");
1059*bb4ee6a4SAndroid Build Coastguard Worker         let mut vm = new_vm(cpu_count, mem);
1060*bb4ee6a4SAndroid Build Coastguard Worker         assert!(vm.remove_memory_region(0).is_err());
1061*bb4ee6a4SAndroid Build Coastguard Worker     }
1062*bb4ee6a4SAndroid Build Coastguard Worker 
1063*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
overlap_memory()1064*bb4ee6a4SAndroid Build Coastguard Worker     fn overlap_memory() {
1065*bb4ee6a4SAndroid Build Coastguard Worker         if !Whpx::is_enabled() {
1066*bb4ee6a4SAndroid Build Coastguard Worker             return;
1067*bb4ee6a4SAndroid Build Coastguard Worker         }
1068*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_count = 1;
1069*bb4ee6a4SAndroid Build Coastguard Worker         let mem =
1070*bb4ee6a4SAndroid Build Coastguard Worker             GuestMemory::new(&[(GuestAddress(0), 0x10000)]).expect("failed to create guest memory");
1071*bb4ee6a4SAndroid Build Coastguard Worker         let mut vm = new_vm(cpu_count, mem);
1072*bb4ee6a4SAndroid Build Coastguard Worker         let mem_size = 0x2000;
1073*bb4ee6a4SAndroid Build Coastguard Worker         let shm = SharedMemory::new("test", mem_size as u64).unwrap();
1074*bb4ee6a4SAndroid Build Coastguard Worker         let mem = MemoryMappingBuilder::new(mem_size)
1075*bb4ee6a4SAndroid Build Coastguard Worker             .from_shared_memory(&shm)
1076*bb4ee6a4SAndroid Build Coastguard Worker             .build()
1077*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
1078*bb4ee6a4SAndroid Build Coastguard Worker         assert!(vm
1079*bb4ee6a4SAndroid Build Coastguard Worker             .add_memory_region(
1080*bb4ee6a4SAndroid Build Coastguard Worker                 GuestAddress(0x2000),
1081*bb4ee6a4SAndroid Build Coastguard Worker                 Box::new(mem),
1082*bb4ee6a4SAndroid Build Coastguard Worker                 false,
1083*bb4ee6a4SAndroid Build Coastguard Worker                 false,
1084*bb4ee6a4SAndroid Build Coastguard Worker                 MemCacheType::CacheCoherent
1085*bb4ee6a4SAndroid Build Coastguard Worker             )
1086*bb4ee6a4SAndroid Build Coastguard Worker             .is_err());
1087*bb4ee6a4SAndroid Build Coastguard Worker     }
1088*bb4ee6a4SAndroid Build Coastguard Worker 
1089*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
sync_memory()1090*bb4ee6a4SAndroid Build Coastguard Worker     fn sync_memory() {
1091*bb4ee6a4SAndroid Build Coastguard Worker         if !Whpx::is_enabled() {
1092*bb4ee6a4SAndroid Build Coastguard Worker             return;
1093*bb4ee6a4SAndroid Build Coastguard Worker         }
1094*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_count = 1;
1095*bb4ee6a4SAndroid Build Coastguard Worker         let mem =
1096*bb4ee6a4SAndroid Build Coastguard Worker             GuestMemory::new(&[(GuestAddress(0), 0x1000)]).expect("failed to create guest memory");
1097*bb4ee6a4SAndroid Build Coastguard Worker         let mut vm = new_vm(cpu_count, mem);
1098*bb4ee6a4SAndroid Build Coastguard Worker         let mem_size = 0x1000;
1099*bb4ee6a4SAndroid Build Coastguard Worker         let shm = SharedMemory::new("test", mem_size as u64).unwrap();
1100*bb4ee6a4SAndroid Build Coastguard Worker         let mem = MemoryMappingBuilder::new(mem_size)
1101*bb4ee6a4SAndroid Build Coastguard Worker             .from_shared_memory(&shm)
1102*bb4ee6a4SAndroid Build Coastguard Worker             .build()
1103*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
1104*bb4ee6a4SAndroid Build Coastguard Worker         let slot = vm
1105*bb4ee6a4SAndroid Build Coastguard Worker             .add_memory_region(
1106*bb4ee6a4SAndroid Build Coastguard Worker                 GuestAddress(0x10000),
1107*bb4ee6a4SAndroid Build Coastguard Worker                 Box::new(mem),
1108*bb4ee6a4SAndroid Build Coastguard Worker                 false,
1109*bb4ee6a4SAndroid Build Coastguard Worker                 false,
1110*bb4ee6a4SAndroid Build Coastguard Worker                 MemCacheType::CacheCoherent,
1111*bb4ee6a4SAndroid Build Coastguard Worker             )
1112*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
1113*bb4ee6a4SAndroid Build Coastguard Worker         vm.msync_memory_region(slot, mem_size - 1, 0).unwrap();
1114*bb4ee6a4SAndroid Build Coastguard Worker         vm.msync_memory_region(slot, 0, mem_size).unwrap();
1115*bb4ee6a4SAndroid Build Coastguard Worker         assert!(vm.msync_memory_region(slot, mem_size, 0).is_err());
1116*bb4ee6a4SAndroid Build Coastguard Worker         assert!(vm.msync_memory_region(slot + 1, mem_size, 0).is_err());
1117*bb4ee6a4SAndroid Build Coastguard Worker     }
1118*bb4ee6a4SAndroid Build Coastguard Worker }
1119