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