1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 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 //! vm_control API client for use within crosvm 6*bb4ee6a4SAndroid Build Coastguard Worker 7*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor; 8*bb4ee6a4SAndroid Build Coastguard Worker use base::Event; 9*bb4ee6a4SAndroid Build Coastguard Worker use base::Protection; 10*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor; 11*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube; 12*bb4ee6a4SAndroid Build Coastguard Worker use base::TubeError; 13*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::Datamatch; 14*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::MemCacheType; 15*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted; 16*bb4ee6a4SAndroid Build Coastguard Worker use resources::Alloc; 17*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize; 18*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize; 19*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error; 20*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress; 21*bb4ee6a4SAndroid Build Coastguard Worker 22*bb4ee6a4SAndroid Build Coastguard Worker use crate::IoEventUpdateRequest; 23*bb4ee6a4SAndroid Build Coastguard Worker use crate::VmMemoryDestination; 24*bb4ee6a4SAndroid Build Coastguard Worker use crate::VmMemoryRegionId; 25*bb4ee6a4SAndroid Build Coastguard Worker use crate::VmMemoryRequest; 26*bb4ee6a4SAndroid Build Coastguard Worker use crate::VmMemoryResponse; 27*bb4ee6a4SAndroid Build Coastguard Worker use crate::VmMemorySource; 28*bb4ee6a4SAndroid Build Coastguard Worker 29*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)] 30*bb4ee6a4SAndroid Build Coastguard Worker #[sorted] 31*bb4ee6a4SAndroid Build Coastguard Worker pub enum ApiClientError { 32*bb4ee6a4SAndroid Build Coastguard Worker #[error("API client tube recv failed: {0}")] 33*bb4ee6a4SAndroid Build Coastguard Worker Recv(TubeError), 34*bb4ee6a4SAndroid Build Coastguard Worker #[error("Request failed: {0}")] 35*bb4ee6a4SAndroid Build Coastguard Worker RequestFailed(#[from] base::Error), 36*bb4ee6a4SAndroid Build Coastguard Worker #[error("API client tube send failed: {0}")] 37*bb4ee6a4SAndroid Build Coastguard Worker Send(TubeError), 38*bb4ee6a4SAndroid Build Coastguard Worker #[error("API client tube sending FDs failed: {0}")] 39*bb4ee6a4SAndroid Build Coastguard Worker SendFds(TubeError), 40*bb4ee6a4SAndroid Build Coastguard Worker #[error("Unexpected tube response")] 41*bb4ee6a4SAndroid Build Coastguard Worker UnexpectedResponse, 42*bb4ee6a4SAndroid Build Coastguard Worker } 43*bb4ee6a4SAndroid Build Coastguard Worker 44*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = std::result::Result<T, ApiClientError>; 45*bb4ee6a4SAndroid Build Coastguard Worker 46*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)] 47*bb4ee6a4SAndroid Build Coastguard Worker pub struct VmMemoryClient { 48*bb4ee6a4SAndroid Build Coastguard Worker tube: Tube, 49*bb4ee6a4SAndroid Build Coastguard Worker } 50*bb4ee6a4SAndroid Build Coastguard Worker 51*bb4ee6a4SAndroid Build Coastguard Worker impl VmMemoryClient { new(tube: Tube) -> Self52*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(tube: Tube) -> Self { 53*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryClient { tube } 54*bb4ee6a4SAndroid Build Coastguard Worker } 55*bb4ee6a4SAndroid Build Coastguard Worker request(&self, request: &VmMemoryRequest) -> Result<VmMemoryResponse>56*bb4ee6a4SAndroid Build Coastguard Worker fn request(&self, request: &VmMemoryRequest) -> Result<VmMemoryResponse> { 57*bb4ee6a4SAndroid Build Coastguard Worker self.tube.send(request).map_err(ApiClientError::Send)?; 58*bb4ee6a4SAndroid Build Coastguard Worker self.tube 59*bb4ee6a4SAndroid Build Coastguard Worker .recv::<VmMemoryResponse>() 60*bb4ee6a4SAndroid Build Coastguard Worker .map_err(ApiClientError::Recv) 61*bb4ee6a4SAndroid Build Coastguard Worker } 62*bb4ee6a4SAndroid Build Coastguard Worker request_unit(&self, request: &VmMemoryRequest) -> Result<()>63*bb4ee6a4SAndroid Build Coastguard Worker fn request_unit(&self, request: &VmMemoryRequest) -> Result<()> { 64*bb4ee6a4SAndroid Build Coastguard Worker match self.request(request)? { 65*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryResponse::Ok => Ok(()), 66*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryResponse::Err(e) => Err(ApiClientError::RequestFailed(e)), 67*bb4ee6a4SAndroid Build Coastguard Worker _other => Err(ApiClientError::UnexpectedResponse), 68*bb4ee6a4SAndroid Build Coastguard Worker } 69*bb4ee6a4SAndroid Build Coastguard Worker } 70*bb4ee6a4SAndroid Build Coastguard Worker 71*bb4ee6a4SAndroid Build Coastguard Worker /// Prepare a shared memory region to make later operations more efficient. This 72*bb4ee6a4SAndroid Build Coastguard Worker /// may be a no-op depending on underlying platform support. prepare_shared_memory_region(&self, alloc: Alloc, cache: MemCacheType) -> Result<()>73*bb4ee6a4SAndroid Build Coastguard Worker pub fn prepare_shared_memory_region(&self, alloc: Alloc, cache: MemCacheType) -> Result<()> { 74*bb4ee6a4SAndroid Build Coastguard Worker self.request_unit(&VmMemoryRequest::PrepareSharedMemoryRegion { alloc, cache }) 75*bb4ee6a4SAndroid Build Coastguard Worker } 76*bb4ee6a4SAndroid Build Coastguard Worker register_memory( &self, source: VmMemorySource, dest: VmMemoryDestination, prot: Protection, cache: MemCacheType, ) -> Result<VmMemoryRegionId>77*bb4ee6a4SAndroid Build Coastguard Worker pub fn register_memory( 78*bb4ee6a4SAndroid Build Coastguard Worker &self, 79*bb4ee6a4SAndroid Build Coastguard Worker source: VmMemorySource, 80*bb4ee6a4SAndroid Build Coastguard Worker dest: VmMemoryDestination, 81*bb4ee6a4SAndroid Build Coastguard Worker prot: Protection, 82*bb4ee6a4SAndroid Build Coastguard Worker cache: MemCacheType, 83*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<VmMemoryRegionId> { 84*bb4ee6a4SAndroid Build Coastguard Worker let request = VmMemoryRequest::RegisterMemory { 85*bb4ee6a4SAndroid Build Coastguard Worker source, 86*bb4ee6a4SAndroid Build Coastguard Worker dest, 87*bb4ee6a4SAndroid Build Coastguard Worker prot, 88*bb4ee6a4SAndroid Build Coastguard Worker cache, 89*bb4ee6a4SAndroid Build Coastguard Worker }; 90*bb4ee6a4SAndroid Build Coastguard Worker match self.request(&request)? { 91*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryResponse::Err(e) => Err(ApiClientError::RequestFailed(e)), 92*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryResponse::RegisterMemory { region_id, .. } => Ok(region_id), 93*bb4ee6a4SAndroid Build Coastguard Worker _other => Err(ApiClientError::UnexpectedResponse), 94*bb4ee6a4SAndroid Build Coastguard Worker } 95*bb4ee6a4SAndroid Build Coastguard Worker } 96*bb4ee6a4SAndroid Build Coastguard Worker 97*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))] mmap_and_register_memory( &self, mapping_address: GuestAddress, shm: base::SharedMemory, file_mapping_info: Vec<crate::VmMemoryFileMapping>, ) -> Result<u32>98*bb4ee6a4SAndroid Build Coastguard Worker pub fn mmap_and_register_memory( 99*bb4ee6a4SAndroid Build Coastguard Worker &self, 100*bb4ee6a4SAndroid Build Coastguard Worker mapping_address: GuestAddress, 101*bb4ee6a4SAndroid Build Coastguard Worker shm: base::SharedMemory, 102*bb4ee6a4SAndroid Build Coastguard Worker file_mapping_info: Vec<crate::VmMemoryFileMapping>, 103*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<u32> { 104*bb4ee6a4SAndroid Build Coastguard Worker let num_file_mappings = file_mapping_info.len(); 105*bb4ee6a4SAndroid Build Coastguard Worker let req = VmMemoryRequest::MmapAndRegisterMemory { 106*bb4ee6a4SAndroid Build Coastguard Worker shm, 107*bb4ee6a4SAndroid Build Coastguard Worker dest: VmMemoryDestination::GuestPhysicalAddress(mapping_address.0), 108*bb4ee6a4SAndroid Build Coastguard Worker num_file_mappings, 109*bb4ee6a4SAndroid Build Coastguard Worker }; 110*bb4ee6a4SAndroid Build Coastguard Worker 111*bb4ee6a4SAndroid Build Coastguard Worker self.tube.send(&req).map_err(ApiClientError::Send)?; 112*bb4ee6a4SAndroid Build Coastguard Worker 113*bb4ee6a4SAndroid Build Coastguard Worker // Since the number of FDs that can be sent via Tube at once is limited to 114*bb4ee6a4SAndroid Build Coastguard Worker // SCM_MAX_FD, split `file_mappings` to chunks and send them 115*bb4ee6a4SAndroid Build Coastguard Worker // repeatedly. 116*bb4ee6a4SAndroid Build Coastguard Worker for m in file_mapping_info.chunks(base::unix::SCM_MAX_FD) { 117*bb4ee6a4SAndroid Build Coastguard Worker self.tube 118*bb4ee6a4SAndroid Build Coastguard Worker .send_with_max_fds(&m, m.len()) 119*bb4ee6a4SAndroid Build Coastguard Worker .map_err(ApiClientError::SendFds)?; 120*bb4ee6a4SAndroid Build Coastguard Worker } 121*bb4ee6a4SAndroid Build Coastguard Worker 122*bb4ee6a4SAndroid Build Coastguard Worker match self.tube.recv().map_err(ApiClientError::Recv)? { 123*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryResponse::RegisterMemory { slot, .. } => Ok(slot), 124*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryResponse::Err(e) => Err(ApiClientError::RequestFailed(e)), 125*bb4ee6a4SAndroid Build Coastguard Worker _ => Err(ApiClientError::UnexpectedResponse), 126*bb4ee6a4SAndroid Build Coastguard Worker } 127*bb4ee6a4SAndroid Build Coastguard Worker } 128*bb4ee6a4SAndroid Build Coastguard Worker 129*bb4ee6a4SAndroid Build Coastguard Worker /// Call hypervisor to free the given memory range. dynamically_free_memory_range( &self, guest_address: GuestAddress, size: u64, ) -> Result<()>130*bb4ee6a4SAndroid Build Coastguard Worker pub fn dynamically_free_memory_range( 131*bb4ee6a4SAndroid Build Coastguard Worker &self, 132*bb4ee6a4SAndroid Build Coastguard Worker guest_address: GuestAddress, 133*bb4ee6a4SAndroid Build Coastguard Worker size: u64, 134*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 135*bb4ee6a4SAndroid Build Coastguard Worker self.request_unit(&VmMemoryRequest::DynamicallyFreeMemoryRange { 136*bb4ee6a4SAndroid Build Coastguard Worker guest_address, 137*bb4ee6a4SAndroid Build Coastguard Worker size, 138*bb4ee6a4SAndroid Build Coastguard Worker }) 139*bb4ee6a4SAndroid Build Coastguard Worker } 140*bb4ee6a4SAndroid Build Coastguard Worker 141*bb4ee6a4SAndroid Build Coastguard Worker /// Call hypervisor to reclaim a priorly freed memory range. dynamically_reclaim_memory_range( &self, guest_address: GuestAddress, size: u64, ) -> Result<()>142*bb4ee6a4SAndroid Build Coastguard Worker pub fn dynamically_reclaim_memory_range( 143*bb4ee6a4SAndroid Build Coastguard Worker &self, 144*bb4ee6a4SAndroid Build Coastguard Worker guest_address: GuestAddress, 145*bb4ee6a4SAndroid Build Coastguard Worker size: u64, 146*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 147*bb4ee6a4SAndroid Build Coastguard Worker self.request_unit(&VmMemoryRequest::DynamicallyReclaimMemoryRange { 148*bb4ee6a4SAndroid Build Coastguard Worker guest_address, 149*bb4ee6a4SAndroid Build Coastguard Worker size, 150*bb4ee6a4SAndroid Build Coastguard Worker }) 151*bb4ee6a4SAndroid Build Coastguard Worker } 152*bb4ee6a4SAndroid Build Coastguard Worker 153*bb4ee6a4SAndroid Build Coastguard Worker /// Unregister the given memory slot that was previously registered with `RegisterMemory`. unregister_memory(&self, region: VmMemoryRegionId) -> Result<()>154*bb4ee6a4SAndroid Build Coastguard Worker pub fn unregister_memory(&self, region: VmMemoryRegionId) -> Result<()> { 155*bb4ee6a4SAndroid Build Coastguard Worker self.request_unit(&VmMemoryRequest::UnregisterMemory(region)) 156*bb4ee6a4SAndroid Build Coastguard Worker } 157*bb4ee6a4SAndroid Build Coastguard Worker 158*bb4ee6a4SAndroid Build Coastguard Worker /// Register an ioeventfd by looking up using Alloc info. register_io_event_with_alloc( &self, evt: Event, allocation: Alloc, offset: u64, datamatch: Datamatch, ) -> Result<()>159*bb4ee6a4SAndroid Build Coastguard Worker pub fn register_io_event_with_alloc( 160*bb4ee6a4SAndroid Build Coastguard Worker &self, 161*bb4ee6a4SAndroid Build Coastguard Worker evt: Event, 162*bb4ee6a4SAndroid Build Coastguard Worker allocation: Alloc, 163*bb4ee6a4SAndroid Build Coastguard Worker offset: u64, 164*bb4ee6a4SAndroid Build Coastguard Worker datamatch: Datamatch, 165*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 166*bb4ee6a4SAndroid Build Coastguard Worker self.request_unit(&VmMemoryRequest::IoEventWithAlloc { 167*bb4ee6a4SAndroid Build Coastguard Worker evt, 168*bb4ee6a4SAndroid Build Coastguard Worker allocation, 169*bb4ee6a4SAndroid Build Coastguard Worker offset, 170*bb4ee6a4SAndroid Build Coastguard Worker datamatch, 171*bb4ee6a4SAndroid Build Coastguard Worker register: true, 172*bb4ee6a4SAndroid Build Coastguard Worker }) 173*bb4ee6a4SAndroid Build Coastguard Worker } 174*bb4ee6a4SAndroid Build Coastguard Worker 175*bb4ee6a4SAndroid Build Coastguard Worker /// Unregister an eventfd by looking up using Alloc info. unregister_io_event_with_alloc( &self, evt: Event, allocation: Alloc, offset: u64, datamatch: Datamatch, ) -> Result<()>176*bb4ee6a4SAndroid Build Coastguard Worker pub fn unregister_io_event_with_alloc( 177*bb4ee6a4SAndroid Build Coastguard Worker &self, 178*bb4ee6a4SAndroid Build Coastguard Worker evt: Event, 179*bb4ee6a4SAndroid Build Coastguard Worker allocation: Alloc, 180*bb4ee6a4SAndroid Build Coastguard Worker offset: u64, 181*bb4ee6a4SAndroid Build Coastguard Worker datamatch: Datamatch, 182*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 183*bb4ee6a4SAndroid Build Coastguard Worker self.request_unit(&VmMemoryRequest::IoEventWithAlloc { 184*bb4ee6a4SAndroid Build Coastguard Worker evt, 185*bb4ee6a4SAndroid Build Coastguard Worker allocation, 186*bb4ee6a4SAndroid Build Coastguard Worker offset, 187*bb4ee6a4SAndroid Build Coastguard Worker datamatch, 188*bb4ee6a4SAndroid Build Coastguard Worker register: false, 189*bb4ee6a4SAndroid Build Coastguard Worker }) 190*bb4ee6a4SAndroid Build Coastguard Worker } 191*bb4ee6a4SAndroid Build Coastguard Worker 192*bb4ee6a4SAndroid Build Coastguard Worker /// Register an eventfd with raw guest memory address. register_io_event(&self, event: Event, addr: u64, datamatch: Datamatch) -> Result<()>193*bb4ee6a4SAndroid Build Coastguard Worker pub fn register_io_event(&self, event: Event, addr: u64, datamatch: Datamatch) -> Result<()> { 194*bb4ee6a4SAndroid Build Coastguard Worker self.request_unit(&VmMemoryRequest::IoEventRaw(IoEventUpdateRequest { 195*bb4ee6a4SAndroid Build Coastguard Worker event, 196*bb4ee6a4SAndroid Build Coastguard Worker addr, 197*bb4ee6a4SAndroid Build Coastguard Worker datamatch, 198*bb4ee6a4SAndroid Build Coastguard Worker register: true, 199*bb4ee6a4SAndroid Build Coastguard Worker })) 200*bb4ee6a4SAndroid Build Coastguard Worker } 201*bb4ee6a4SAndroid Build Coastguard Worker 202*bb4ee6a4SAndroid Build Coastguard Worker /// Unregister an eventfd with raw guest memory address. unregister_io_event(&self, event: Event, addr: u64, datamatch: Datamatch) -> Result<()>203*bb4ee6a4SAndroid Build Coastguard Worker pub fn unregister_io_event(&self, event: Event, addr: u64, datamatch: Datamatch) -> Result<()> { 204*bb4ee6a4SAndroid Build Coastguard Worker self.request_unit(&VmMemoryRequest::IoEventRaw(IoEventUpdateRequest { 205*bb4ee6a4SAndroid Build Coastguard Worker event, 206*bb4ee6a4SAndroid Build Coastguard Worker addr, 207*bb4ee6a4SAndroid Build Coastguard Worker datamatch, 208*bb4ee6a4SAndroid Build Coastguard Worker register: false, 209*bb4ee6a4SAndroid Build Coastguard Worker })) 210*bb4ee6a4SAndroid Build Coastguard Worker } 211*bb4ee6a4SAndroid Build Coastguard Worker balloon_target_reached(&self, size: u64) -> Result<()>212*bb4ee6a4SAndroid Build Coastguard Worker pub fn balloon_target_reached(&self, size: u64) -> Result<()> { 213*bb4ee6a4SAndroid Build Coastguard Worker self.request_unit(&VmMemoryRequest::BalloonTargetReached { size }) 214*bb4ee6a4SAndroid Build Coastguard Worker } 215*bb4ee6a4SAndroid Build Coastguard Worker } 216*bb4ee6a4SAndroid Build Coastguard Worker 217*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for VmMemoryClient { as_raw_descriptor(&self) -> RawDescriptor218*bb4ee6a4SAndroid Build Coastguard Worker fn as_raw_descriptor(&self) -> RawDescriptor { 219*bb4ee6a4SAndroid Build Coastguard Worker self.tube.as_raw_descriptor() 220*bb4ee6a4SAndroid Build Coastguard Worker } 221*bb4ee6a4SAndroid Build Coastguard Worker } 222