1use base::AsRawDescriptor;
8use base::Event;
9use base::Protection;
10use base::RawDescriptor;
11use base::Tube;
12use base::TubeError;
13use hypervisor::Datamatch;
14use hypervisor::MemCacheType;
15use remain::sorted;
16use resources::Alloc;
17use serde::Deserialize;
18use serde::Serialize;
19use thiserror::Error;
20use vm_memory::GuestAddress;
21
22use crate::IoEventUpdateRequest;
23use crate::VmMemoryDestination;
24use crate::VmMemoryRegionId;
25use crate::VmMemoryRequest;
26use crate::VmMemoryResponse;
27use crate::VmMemoryResponseError;
28use crate::VmMemorySource;
29
30#[derive(Error, Debug)]
31#[sorted]
32pub enum ApiClientError {
33 #[error("API client tube recv failed: {0}")]
34 Recv(TubeError),
35 #[error("Request failed: {0}")]
36 RequestFailed(#[source] anyhow::Error),
37 #[error("API client tube send failed: {0}")]
38 Send(TubeError),
39 #[error("API client tube sending FDs failed: {0}")]
40 SendFds(TubeError),
41 #[error("Unexpected tube response")]
42 UnexpectedResponse,
43}
44
45pub type Result<T> = std::result::Result<T, ApiClientError>;
46
47#[derive(Serialize, Deserialize)]
48pub struct VmMemoryClient {
49 tube: Tube,
50}
51
52impl VmMemoryClient {
53 pub fn new(tube: Tube) -> Self {
54 VmMemoryClient { tube }
55 }
56
57 fn request(&self, request: &VmMemoryRequest) -> Result<VmMemoryResponse> {
58 self.tube.send(request).map_err(ApiClientError::Send)?;
59 self.tube
60 .recv::<VmMemoryResponse>()
61 .map_err(ApiClientError::Recv)
62 }
63
64 fn request_unit(&self, request: &VmMemoryRequest) -> Result<()> {
65 match self.request(request)? {
66 VmMemoryResponse::Ok => Ok(()),
67 VmMemoryResponse::Err(VmMemoryResponseError(e)) => {
68 Err(ApiClientError::RequestFailed(e))
69 }
70 _other => Err(ApiClientError::UnexpectedResponse),
71 }
72 }
73
74 pub fn prepare_shared_memory_region(&self, alloc: Alloc, cache: MemCacheType) -> Result<()> {
77 self.request_unit(&VmMemoryRequest::PrepareSharedMemoryRegion { alloc, cache })
78 }
79
80 pub fn register_memory(
81 &self,
82 source: VmMemorySource,
83 dest: VmMemoryDestination,
84 prot: Protection,
85 cache: MemCacheType,
86 ) -> Result<VmMemoryRegionId> {
87 let request = VmMemoryRequest::RegisterMemory {
88 source,
89 dest,
90 prot,
91 cache,
92 };
93 match self.request(&request)? {
94 VmMemoryResponse::Err(VmMemoryResponseError(e)) => {
95 Err(ApiClientError::RequestFailed(e))
96 }
97 VmMemoryResponse::RegisterMemory { region_id, .. } => Ok(region_id),
98 _other => Err(ApiClientError::UnexpectedResponse),
99 }
100 }
101
102 #[cfg(any(target_os = "android", target_os = "linux"))]
103 pub fn mmap_and_register_memory(
104 &self,
105 mapping_address: GuestAddress,
106 shm: base::SharedMemory,
107 file_mapping_info: Vec<crate::VmMemoryFileMapping>,
108 ) -> Result<u32> {
109 let num_file_mappings = file_mapping_info.len();
110 let req = VmMemoryRequest::MmapAndRegisterMemory {
111 shm,
112 dest: VmMemoryDestination::GuestPhysicalAddress(mapping_address.0),
113 num_file_mappings,
114 };
115
116 self.tube.send(&req).map_err(ApiClientError::Send)?;
117
118 for m in file_mapping_info.chunks(base::unix::SCM_MAX_FD) {
122 self.tube
123 .send_with_max_fds(&m, m.len())
124 .map_err(ApiClientError::SendFds)?;
125 }
126
127 match self.tube.recv().map_err(ApiClientError::Recv)? {
128 VmMemoryResponse::RegisterMemory { slot, .. } => Ok(slot),
129 VmMemoryResponse::Err(VmMemoryResponseError(e)) => {
130 Err(ApiClientError::RequestFailed(e))
131 }
132 _ => Err(ApiClientError::UnexpectedResponse),
133 }
134 }
135
136 pub fn dynamically_free_memory_ranges(&self, ranges: Vec<(GuestAddress, u64)>) -> Result<()> {
138 self.request_unit(&VmMemoryRequest::DynamicallyFreeMemoryRanges { ranges })
139 }
140
141 pub fn dynamically_reclaim_memory_ranges(
143 &self,
144 ranges: Vec<(GuestAddress, u64)>,
145 ) -> Result<()> {
146 self.request_unit(&VmMemoryRequest::DynamicallyReclaimMemoryRanges { ranges })
147 }
148
149 pub fn unregister_memory(&self, region: VmMemoryRegionId) -> Result<()> {
151 self.request_unit(&VmMemoryRequest::UnregisterMemory(region))
152 }
153
154 pub fn register_io_event(&self, event: Event, addr: u64, datamatch: Datamatch) -> Result<()> {
156 self.request_unit(&VmMemoryRequest::IoEventRaw(IoEventUpdateRequest {
157 event,
158 addr,
159 datamatch,
160 register: true,
161 }))
162 }
163
164 pub fn unregister_io_event(&self, event: Event, addr: u64, datamatch: Datamatch) -> Result<()> {
166 self.request_unit(&VmMemoryRequest::IoEventRaw(IoEventUpdateRequest {
167 event,
168 addr,
169 datamatch,
170 register: false,
171 }))
172 }
173
174 pub fn balloon_target_reached(&self, size: u64) -> Result<()> {
175 self.request_unit(&VmMemoryRequest::BalloonTargetReached { size })
176 }
177}
178
179impl AsRawDescriptor for VmMemoryClient {
180 fn as_raw_descriptor(&self) -> RawDescriptor {
181 self.tube.as_raw_descriptor()
182 }
183}