1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #[cfg(feature = "gpu")]
6 pub(crate) mod gpu;
7
8 use std::path::Path;
9
10 use base::error;
11 use base::AsRawDescriptor;
12 use base::Descriptor;
13 use base::Error as SysError;
14 use base::MemoryMappingArena;
15 use base::MmapError;
16 use base::Protection;
17 use base::SafeDescriptor;
18 use base::Tube;
19 use base::UnixSeqpacket;
20 use hypervisor::MemSlot;
21 use hypervisor::Vm;
22 use libc::EINVAL;
23 use libc::ERANGE;
24 use resources::Alloc;
25 use resources::SystemAllocator;
26 use serde::Deserialize;
27 use serde::Serialize;
28 use vm_memory::GuestAddress;
29
30 use crate::client::HandleRequestResult;
31 use crate::VmRequest;
32 use crate::VmResponse;
33
handle_request<T: AsRef<Path> + std::fmt::Debug>( request: &VmRequest, socket_path: T, ) -> HandleRequestResult34 pub fn handle_request<T: AsRef<Path> + std::fmt::Debug>(
35 request: &VmRequest,
36 socket_path: T,
37 ) -> HandleRequestResult {
38 match UnixSeqpacket::connect(&socket_path) {
39 Ok(s) => {
40 let socket = Tube::new_from_unix_seqpacket(s);
41 if let Err(e) = socket.send(request) {
42 error!(
43 "failed to send request to socket at '{:?}': {}",
44 socket_path, e
45 );
46 return Err(());
47 }
48 match socket.recv() {
49 Ok(response) => Ok(response),
50 Err(e) => {
51 error!(
52 "failed to recv response from socket at '{:?}': {}",
53 socket_path, e
54 );
55 Err(())
56 }
57 }
58 }
59 Err(e) => {
60 error!("failed to connect to socket at '{:?}': {}", socket_path, e);
61 Err(())
62 }
63 }
64 }
65
66 #[derive(Serialize, Deserialize, Debug)]
67 pub enum VmMsyncRequest {
68 /// Flush the content of a memory mapping to its backing file.
69 /// `slot` selects the arena (as returned by `Vm::add_mmap_arena`).
70 /// `offset` is the offset of the mapping to sync within the arena.
71 /// `size` is the size of the mapping to sync within the arena.
72 MsyncArena {
73 slot: MemSlot,
74 offset: usize,
75 size: usize,
76 },
77 }
78
79 #[derive(Serialize, Deserialize, Debug)]
80 pub enum VmMsyncResponse {
81 Ok,
82 Err(SysError),
83 }
84
85 impl VmMsyncRequest {
86 /// Executes this request on the given Vm.
87 ///
88 /// # Arguments
89 /// * `vm` - The `Vm` to perform the request on.
90 ///
91 /// This does not return a result, instead encapsulating the success or failure in a
92 /// `VmMsyncResponse` with the intended purpose of sending the response back over the socket
93 /// that received this `VmMsyncResponse`.
execute(&self, vm: &mut impl Vm) -> VmMsyncResponse94 pub fn execute(&self, vm: &mut impl Vm) -> VmMsyncResponse {
95 use self::VmMsyncRequest::*;
96 match *self {
97 MsyncArena { slot, offset, size } => match vm.msync_memory_region(slot, offset, size) {
98 Ok(()) => VmMsyncResponse::Ok,
99 Err(e) => VmMsyncResponse::Err(e),
100 },
101 }
102 }
103 }
104
105 #[derive(Serialize, Deserialize, Debug)]
106 pub enum FsMappingRequest {
107 /// Create an anonymous memory mapping that spans the entire region described by `Alloc`.
108 AllocateSharedMemoryRegion(Alloc),
109 /// Create a memory mapping.
110 CreateMemoryMapping {
111 /// The slot for a MemoryMappingArena, previously returned by a response to an
112 /// `AllocateSharedMemoryRegion` request.
113 slot: u32,
114 /// The file descriptor that should be mapped.
115 fd: SafeDescriptor,
116 /// The size of the mapping.
117 size: usize,
118 /// The offset into the file from where the mapping should start.
119 file_offset: u64,
120 /// The memory protection to be used for the mapping. Protections other than readable and
121 /// writable will be silently dropped.
122 prot: Protection,
123 /// The offset into the shared memory region where the mapping should be placed.
124 mem_offset: usize,
125 },
126 /// Remove a memory mapping.
127 RemoveMemoryMapping {
128 /// The slot for a MemoryMappingArena.
129 slot: u32,
130 /// The offset into the shared memory region.
131 offset: usize,
132 /// The size of the mapping.
133 size: usize,
134 },
135 }
136
137 impl FsMappingRequest {
execute(&self, vm: &mut dyn Vm, allocator: &mut SystemAllocator) -> VmResponse138 pub fn execute(&self, vm: &mut dyn Vm, allocator: &mut SystemAllocator) -> VmResponse {
139 use self::FsMappingRequest::*;
140 match *self {
141 AllocateSharedMemoryRegion(Alloc::PciBar {
142 bus,
143 dev,
144 func,
145 bar,
146 }) => {
147 match allocator.mmio_allocator_any().get(&Alloc::PciBar {
148 bus,
149 dev,
150 func,
151 bar,
152 }) {
153 Some((range, _)) => {
154 let size: usize = match range.len().and_then(|x| x.try_into().ok()) {
155 Some(v) => v,
156 None => return VmResponse::Err(SysError::new(ERANGE)),
157 };
158 let arena = match MemoryMappingArena::new(size) {
159 Ok(a) => a,
160 Err(MmapError::SystemCallFailed(e)) => return VmResponse::Err(e),
161 _ => return VmResponse::Err(SysError::new(EINVAL)),
162 };
163
164 match vm.add_memory_region(
165 GuestAddress(range.start),
166 Box::new(arena),
167 false,
168 false,
169 ) {
170 Ok(slot) => VmResponse::RegisterMemory {
171 pfn: range.start >> 12,
172 slot,
173 },
174 Err(e) => VmResponse::Err(e),
175 }
176 }
177 None => VmResponse::Err(SysError::new(EINVAL)),
178 }
179 }
180 CreateMemoryMapping {
181 slot,
182 ref fd,
183 size,
184 file_offset,
185 prot,
186 mem_offset,
187 } => {
188 let raw_fd: Descriptor = Descriptor(fd.as_raw_descriptor());
189
190 match vm.add_fd_mapping(slot, mem_offset, size, &raw_fd, file_offset, prot) {
191 Ok(()) => VmResponse::Ok,
192 Err(e) => VmResponse::Err(e),
193 }
194 }
195 RemoveMemoryMapping { slot, offset, size } => {
196 match vm.remove_mapping(slot, offset, size) {
197 Ok(()) => VmResponse::Ok,
198 Err(e) => VmResponse::Err(e),
199 }
200 }
201 _ => VmResponse::Err(SysError::new(EINVAL)),
202 }
203 }
204 }
205