1#[cfg(feature = "gpu")]
6pub(crate) mod gpu;
7
8use std::path::Path;
9use std::sync::LazyLock;
10use std::time::Duration;
11
12use base::error;
13use base::AsRawDescriptor;
14use base::Descriptor;
15use base::Error as SysError;
16use base::MemoryMappingArena;
17use base::MmapError;
18use base::Protection;
19use base::SafeDescriptor;
20use base::Tube;
21use base::UnixSeqpacket;
22use hypervisor::MemCacheType;
23use hypervisor::MemSlot;
24use hypervisor::Vm;
25use libc::EINVAL;
26use libc::ERANGE;
27use resources::Alloc;
28use resources::SystemAllocator;
29use serde::Deserialize;
30use serde::Serialize;
31use vm_memory::GuestAddress;
32
33use crate::client::HandleRequestResult;
34use crate::VmMappedMemoryRegion;
35use crate::VmRequest;
36use crate::VmResponse;
37
38pub fn handle_request<T: AsRef<Path> + std::fmt::Debug>(
39 request: &VmRequest,
40 socket_path: T,
41) -> HandleRequestResult {
42 handle_request_with_timeout(request, socket_path, None)
43}
44
45pub fn handle_request_with_timeout<T: AsRef<Path> + std::fmt::Debug>(
46 request: &VmRequest,
47 socket_path: T,
48 timeout: Option<Duration>,
49) -> HandleRequestResult {
50 match UnixSeqpacket::connect(&socket_path) {
51 Ok(s) => {
52 let socket = Tube::try_from(s).map_err(|_| ())?;
53 if timeout.is_some() {
54 if let Err(e) = socket.set_recv_timeout(timeout) {
55 error!(
56 "failed to set recv timeout on socket at '{:?}': {}",
57 socket_path, e
58 );
59 return Err(());
60 }
61 }
62 if let Err(e) = socket.send(request) {
63 error!(
64 "failed to send request to socket at '{:?}': {}",
65 socket_path, e
66 );
67 return Err(());
68 }
69 match socket.recv() {
70 Ok(response) => Ok(response),
71 Err(e) => {
72 error!(
73 "failed to recv response from socket at '{:?}': {}",
74 socket_path, e
75 );
76 Err(())
77 }
78 }
79 }
80 Err(e) => {
81 error!("failed to connect to socket at '{:?}': {}", socket_path, e);
82 Err(())
83 }
84 }
85}
86
87#[derive(Serialize, Deserialize, Debug)]
88pub enum VmMemoryMappingRequest {
89 MsyncArena {
94 slot: MemSlot,
95 offset: usize,
96 size: usize,
97 },
98
99 MadvisePageout {
102 slot: MemSlot,
103 offset: usize,
104 size: usize,
105 },
106
107 MadviseRemove {
110 slot: MemSlot,
111 offset: usize,
112 size: usize,
113 },
114}
115
116#[derive(Serialize, Deserialize, Debug)]
117pub enum VmMemoryMappingResponse {
118 Ok,
119 Err(SysError),
120}
121
122impl VmMemoryMappingRequest {
123 pub fn execute(&self, vm: &mut impl Vm) -> VmMemoryMappingResponse {
132 use self::VmMemoryMappingRequest::*;
133 match *self {
134 MsyncArena { slot, offset, size } => match vm.msync_memory_region(slot, offset, size) {
135 Ok(()) => VmMemoryMappingResponse::Ok,
136 Err(e) => VmMemoryMappingResponse::Err(e),
137 },
138 MadvisePageout { slot, offset, size } => {
139 match vm.madvise_pageout_memory_region(slot, offset, size) {
140 Ok(()) => VmMemoryMappingResponse::Ok,
141 Err(e) => VmMemoryMappingResponse::Err(e),
142 }
143 }
144 MadviseRemove { slot, offset, size } => {
145 match vm.madvise_remove_memory_region(slot, offset, size) {
146 Ok(()) => VmMemoryMappingResponse::Ok,
147 Err(e) => VmMemoryMappingResponse::Err(e),
148 }
149 }
150 }
151 }
152}
153
154#[derive(Serialize, Deserialize, Debug)]
155pub enum FsMappingRequest {
156 AllocateSharedMemoryRegion(Alloc),
158 CreateMemoryMapping {
160 slot: u32,
163 fd: SafeDescriptor,
165 size: usize,
167 file_offset: u64,
169 prot: Protection,
172 mem_offset: usize,
174 },
175 RemoveMemoryMapping {
177 slot: u32,
179 offset: usize,
181 size: usize,
183 },
184}
185
186pub fn prepare_shared_memory_region(
187 vm: &mut dyn Vm,
188 allocator: &mut SystemAllocator,
189 alloc: Alloc,
190 cache: MemCacheType,
191) -> Result<VmMappedMemoryRegion, SysError> {
192 if !matches!(alloc, Alloc::PciBar { .. }) {
193 return Err(SysError::new(EINVAL));
194 }
195 match allocator.mmio_allocator_any().get(&alloc) {
196 Some((range, _)) => {
197 let size: usize = match range.len().and_then(|x| x.try_into().ok()) {
198 Some(v) => v,
199 None => return Err(SysError::new(ERANGE)),
200 };
201 let arena = match MemoryMappingArena::new(size) {
202 Ok(a) => a,
203 Err(MmapError::SystemCallFailed(e)) => return Err(e),
204 _ => return Err(SysError::new(EINVAL)),
205 };
206
207 match vm.add_memory_region(
208 GuestAddress(range.start),
209 Box::new(arena),
210 false,
211 false,
212 cache,
213 ) {
214 Ok(slot) => Ok(VmMappedMemoryRegion {
215 guest_address: GuestAddress(range.start),
216 slot,
217 }),
218 Err(e) => Err(e),
219 }
220 }
221 None => Err(SysError::new(EINVAL)),
222 }
223}
224
225static SHOULD_PREPARE_MEMORY_REGION: LazyLock<bool> = LazyLock::new(|| {
226 if cfg!(target_arch = "x86_64") {
227 match std::fs::read("/sys/module/kvm/parameters/tdp_mmu") {
232 Ok(bytes) if !bytes.is_empty() => bytes[0] == b'Y',
233 _ => false,
234 }
235 } else if cfg!(target_pointer_width = "64") {
236 true
237 } else {
238 false
240 }
241});
242
243pub fn should_prepare_memory_region() -> bool {
244 *SHOULD_PREPARE_MEMORY_REGION
245}
246
247impl FsMappingRequest {
248 pub fn execute(&self, vm: &mut dyn Vm, allocator: &mut SystemAllocator) -> VmResponse {
249 use self::FsMappingRequest::*;
250 match *self {
251 AllocateSharedMemoryRegion(alloc) => {
252 match prepare_shared_memory_region(
253 vm,
254 allocator,
255 alloc,
256 MemCacheType::CacheCoherent,
257 ) {
258 Ok(VmMappedMemoryRegion { slot, .. }) => VmResponse::RegisterMemory { slot },
259 Err(e) => VmResponse::Err(e),
260 }
261 }
262 CreateMemoryMapping {
263 slot,
264 ref fd,
265 size,
266 file_offset,
267 prot,
268 mem_offset,
269 } => {
270 let raw_fd: Descriptor = Descriptor(fd.as_raw_descriptor());
271
272 match vm.add_fd_mapping(slot, mem_offset, size, &raw_fd, file_offset, prot) {
273 Ok(()) => VmResponse::Ok,
274 Err(e) => VmResponse::Err(e),
275 }
276 }
277 RemoveMemoryMapping { slot, offset, size } => {
278 match vm.remove_mapping(slot, offset, size) {
279 Ok(()) => VmResponse::Ok,
280 Err(e) => VmResponse::Err(e),
281 }
282 }
283 }
284 }
285}