• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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