xref: /aosp_15_r20/external/crosvm/vm_control/src/api.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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