• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 use std::cell::RefCell;
6 use std::collections::BTreeMap;
7 use std::path::PathBuf;
8 use std::rc::Rc;
9 use std::sync::Arc;
10 use std::thread;
11 use std::time::Duration;
12 use std::time::Instant;
13 
14 use anyhow::anyhow;
15 use anyhow::bail;
16 use anyhow::Context;
17 use argh::FromArgs;
18 use base::clone_descriptor;
19 use base::error;
20 use base::warn;
21 use base::SafeDescriptor;
22 use base::Tube;
23 use base::UnixSeqpacket;
24 use cros_async::AsyncWrapper;
25 use cros_async::EventAsync;
26 use cros_async::Executor;
27 use cros_async::IoSource;
28 use hypervisor::ProtectionType;
29 #[cfg(feature = "minigbm")]
30 use rutabaga_gfx::RutabagaGralloc;
31 #[cfg(feature = "minigbm")]
32 use rutabaga_gfx::RutabagaGrallocBackendFlags;
33 use vm_memory::GuestMemory;
34 use vmm_vhost::message::VhostUserProtocolFeatures;
35 use vmm_vhost::VHOST_USER_F_PROTOCOL_FEATURES;
36 
37 use crate::virtio::base_features;
38 use crate::virtio::device_constants::wl::NUM_QUEUES;
39 use crate::virtio::device_constants::wl::VIRTIO_WL_F_SEND_FENCES;
40 use crate::virtio::device_constants::wl::VIRTIO_WL_F_TRANS_FLAGS;
41 use crate::virtio::device_constants::wl::VIRTIO_WL_F_USE_SHMEM;
42 use crate::virtio::vhost::user::device::handler::Error as DeviceError;
43 use crate::virtio::vhost::user::device::handler::VhostBackendReqConnection;
44 use crate::virtio::vhost::user::device::handler::VhostBackendReqConnectionState;
45 use crate::virtio::vhost::user::device::handler::VhostUserDevice;
46 use crate::virtio::vhost::user::device::handler::WorkerState;
47 use crate::virtio::vhost::user::device::listener::sys::VhostUserListener;
48 use crate::virtio::vhost::user::device::listener::VhostUserListenerTrait;
49 use crate::virtio::wl;
50 use crate::virtio::Interrupt;
51 use crate::virtio::Queue;
52 use crate::virtio::SharedMemoryRegion;
53 
run_out_queue( queue: Rc<RefCell<Queue>>, doorbell: Interrupt, kick_evt: EventAsync, wlstate: Rc<RefCell<wl::WlState>>, )54 async fn run_out_queue(
55     queue: Rc<RefCell<Queue>>,
56     doorbell: Interrupt,
57     kick_evt: EventAsync,
58     wlstate: Rc<RefCell<wl::WlState>>,
59 ) {
60     loop {
61         if let Err(e) = kick_evt.next_val().await {
62             error!("Failed to read kick event for out queue: {}", e);
63             break;
64         }
65 
66         wl::process_out_queue(
67             &doorbell,
68             &mut queue.borrow_mut(),
69             &mut wlstate.borrow_mut(),
70         );
71     }
72 }
73 
run_in_queue( queue: Rc<RefCell<Queue>>, doorbell: Interrupt, kick_evt: EventAsync, wlstate: Rc<RefCell<wl::WlState>>, wlstate_ctx: IoSource<AsyncWrapper<SafeDescriptor>>, )74 async fn run_in_queue(
75     queue: Rc<RefCell<Queue>>,
76     doorbell: Interrupt,
77     kick_evt: EventAsync,
78     wlstate: Rc<RefCell<wl::WlState>>,
79     wlstate_ctx: IoSource<AsyncWrapper<SafeDescriptor>>,
80 ) {
81     loop {
82         if let Err(e) = wlstate_ctx.wait_readable().await {
83             error!(
84                 "Failed to wait for inner WaitContext to become readable: {}",
85                 e
86             );
87             break;
88         }
89 
90         if wl::process_in_queue(
91             &doorbell,
92             &mut queue.borrow_mut(),
93             &mut wlstate.borrow_mut(),
94         ) == Err(wl::DescriptorsExhausted)
95         {
96             if let Err(e) = kick_evt.next_val().await {
97                 error!("Failed to read kick event for in queue: {}", e);
98                 break;
99             }
100         }
101     }
102 }
103 
104 struct WlBackend {
105     ex: Executor,
106     wayland_paths: Option<BTreeMap<String, PathBuf>>,
107     resource_bridge: Option<Tube>,
108     use_transition_flags: bool,
109     use_send_vfd_v2: bool,
110     use_shmem: bool,
111     features: u64,
112     acked_features: u64,
113     wlstate: Option<Rc<RefCell<wl::WlState>>>,
114     workers: [Option<WorkerState<Rc<RefCell<Queue>>, ()>>; NUM_QUEUES],
115     backend_req_conn: VhostBackendReqConnectionState,
116 }
117 
118 impl WlBackend {
new( ex: &Executor, wayland_paths: BTreeMap<String, PathBuf>, resource_bridge: Option<Tube>, ) -> WlBackend119     fn new(
120         ex: &Executor,
121         wayland_paths: BTreeMap<String, PathBuf>,
122         resource_bridge: Option<Tube>,
123     ) -> WlBackend {
124         let features = base_features(ProtectionType::Unprotected)
125             | 1 << VIRTIO_WL_F_TRANS_FLAGS
126             | 1 << VIRTIO_WL_F_SEND_FENCES
127             | 1 << VIRTIO_WL_F_USE_SHMEM
128             | 1 << VHOST_USER_F_PROTOCOL_FEATURES;
129         WlBackend {
130             ex: ex.clone(),
131             wayland_paths: Some(wayland_paths),
132             resource_bridge,
133             use_transition_flags: false,
134             use_send_vfd_v2: false,
135             use_shmem: false,
136             features,
137             acked_features: 0,
138             wlstate: None,
139             workers: Default::default(),
140             backend_req_conn: VhostBackendReqConnectionState::NoConnection,
141         }
142     }
143 }
144 
145 impl VhostUserDevice for WlBackend {
max_queue_num(&self) -> usize146     fn max_queue_num(&self) -> usize {
147         NUM_QUEUES
148     }
149 
features(&self) -> u64150     fn features(&self) -> u64 {
151         self.features
152     }
153 
ack_features(&mut self, value: u64) -> anyhow::Result<()>154     fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
155         let unrequested_features = value & !self.features();
156         if unrequested_features != 0 {
157             bail!("invalid features are given: {:#x}", unrequested_features);
158         }
159 
160         self.acked_features |= value;
161 
162         if value & (1 << VIRTIO_WL_F_TRANS_FLAGS) != 0 {
163             self.use_transition_flags = true;
164         }
165         if value & (1 << VIRTIO_WL_F_SEND_FENCES) != 0 {
166             self.use_send_vfd_v2 = true;
167         }
168         if value & (1 << VIRTIO_WL_F_USE_SHMEM) != 0 {
169             self.use_shmem = true;
170         }
171 
172         Ok(())
173     }
174 
acked_features(&self) -> u64175     fn acked_features(&self) -> u64 {
176         self.acked_features
177     }
178 
protocol_features(&self) -> VhostUserProtocolFeatures179     fn protocol_features(&self) -> VhostUserProtocolFeatures {
180         VhostUserProtocolFeatures::BACKEND_REQ | VhostUserProtocolFeatures::SHARED_MEMORY_REGIONS
181     }
182 
ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()>183     fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> {
184         if features & self.protocol_features().bits() != self.protocol_features().bits() {
185             Err(anyhow!(
186                 "Acked features {:#x} missing required protocol features",
187                 features
188             ))
189         } else if features & !self.protocol_features().bits() != 0 {
190             Err(anyhow!(
191                 "Acked features {:#x} contains unexpected features",
192                 features
193             ))
194         } else {
195             Ok(())
196         }
197     }
198 
acked_protocol_features(&self) -> u64199     fn acked_protocol_features(&self) -> u64 {
200         VhostUserProtocolFeatures::empty().bits()
201     }
202 
read_config(&self, _offset: u64, _dst: &mut [u8])203     fn read_config(&self, _offset: u64, _dst: &mut [u8]) {}
204 
start_queue( &mut self, idx: usize, queue: Queue, _mem: GuestMemory, doorbell: Interrupt, ) -> anyhow::Result<()>205     fn start_queue(
206         &mut self,
207         idx: usize,
208         queue: Queue,
209         _mem: GuestMemory,
210         doorbell: Interrupt,
211     ) -> anyhow::Result<()> {
212         if self.workers[idx].is_some() {
213             warn!("Starting new queue handler without stopping old handler");
214             self.stop_queue(idx)?;
215         }
216 
217         let kick_evt = queue
218             .event()
219             .try_clone()
220             .context("failed to clone queue event")?;
221         let kick_evt = EventAsync::new(kick_evt, &self.ex)
222             .context("failed to create EventAsync for kick_evt")?;
223 
224         if !self.use_shmem {
225             bail!("Incompatible driver: vhost-user-wl requires shmem support");
226         }
227 
228         // We use this de-structuring let binding to separate borrows so that the compiler doesn't
229         // think we're borrowing all of `self` in the closure below.
230         let WlBackend {
231             ref mut wayland_paths,
232             ref mut resource_bridge,
233             ref use_transition_flags,
234             ref use_send_vfd_v2,
235             ..
236         } = self;
237 
238         #[cfg(feature = "minigbm")]
239         let gralloc = RutabagaGralloc::new(RutabagaGrallocBackendFlags::new())
240             .context("Failed to initailize gralloc")?;
241         let wlstate = match &self.wlstate {
242             None => {
243                 let mapper = {
244                     match &mut self.backend_req_conn {
245                         VhostBackendReqConnectionState::Connected(request) => {
246                             request.take_shmem_mapper()?
247                         }
248                         VhostBackendReqConnectionState::NoConnection => {
249                             bail!("No backend request connection found")
250                         }
251                     }
252                 };
253 
254                 let wlstate = Rc::new(RefCell::new(wl::WlState::new(
255                     wayland_paths.take().expect("WlState already initialized"),
256                     mapper,
257                     *use_transition_flags,
258                     *use_send_vfd_v2,
259                     resource_bridge.take(),
260                     #[cfg(feature = "minigbm")]
261                     gralloc,
262                     None, /* address_offset */
263                 )));
264                 self.wlstate = Some(wlstate.clone());
265                 wlstate
266             }
267             Some(state) => state.clone(),
268         };
269         let queue = Rc::new(RefCell::new(queue));
270         let queue_task = match idx {
271             0 => {
272                 let wlstate_ctx = clone_descriptor(wlstate.borrow().wait_ctx())
273                     .map(AsyncWrapper::new)
274                     .context("failed to clone inner WaitContext for WlState")
275                     .and_then(|ctx| {
276                         self.ex
277                             .async_from(ctx)
278                             .context("failed to create async WaitContext")
279                     })?;
280 
281                 self.ex.spawn_local(run_in_queue(
282                     queue.clone(),
283                     doorbell,
284                     kick_evt,
285                     wlstate,
286                     wlstate_ctx,
287                 ))
288             }
289             1 => self
290                 .ex
291                 .spawn_local(run_out_queue(queue.clone(), doorbell, kick_evt, wlstate)),
292             _ => bail!("attempted to start unknown queue: {}", idx),
293         };
294         self.workers[idx] = Some(WorkerState { queue_task, queue });
295         Ok(())
296     }
297 
stop_queue(&mut self, idx: usize) -> anyhow::Result<Queue>298     fn stop_queue(&mut self, idx: usize) -> anyhow::Result<Queue> {
299         if let Some(worker) = self.workers.get_mut(idx).and_then(Option::take) {
300             // Wait for queue_task to be aborted.
301             let _ = self.ex.run_until(worker.queue_task.cancel());
302 
303             let queue = match Rc::try_unwrap(worker.queue) {
304                 Ok(queue_cell) => queue_cell.into_inner(),
305                 Err(_) => panic!("failed to recover queue from worker"),
306             };
307 
308             Ok(queue)
309         } else {
310             Err(anyhow::Error::new(DeviceError::WorkerNotFound))
311         }
312     }
313 
reset(&mut self)314     fn reset(&mut self) {
315         for worker in self.workers.iter_mut().filter_map(Option::take) {
316             let _ = self.ex.run_until(worker.queue_task.cancel());
317         }
318     }
319 
get_shared_memory_region(&self) -> Option<SharedMemoryRegion>320     fn get_shared_memory_region(&self) -> Option<SharedMemoryRegion> {
321         Some(SharedMemoryRegion {
322             id: wl::WL_SHMEM_ID,
323             length: wl::WL_SHMEM_SIZE,
324         })
325     }
326 
set_backend_req_connection(&mut self, conn: Arc<VhostBackendReqConnection>)327     fn set_backend_req_connection(&mut self, conn: Arc<VhostBackendReqConnection>) {
328         if let VhostBackendReqConnectionState::Connected(_) = &self.backend_req_conn {
329             warn!("connection already established. Overwriting");
330         }
331 
332         self.backend_req_conn = VhostBackendReqConnectionState::Connected(conn);
333     }
334 }
335 
parse_wayland_sock(value: &str) -> Result<(String, PathBuf), String>336 pub fn parse_wayland_sock(value: &str) -> Result<(String, PathBuf), String> {
337     let mut components = value.split(',');
338     let path = PathBuf::from(match components.next() {
339         None => return Err("missing socket path".to_string()),
340         Some(c) => c,
341     });
342     let mut name = "";
343     for c in components {
344         let mut kv = c.splitn(2, '=');
345         let (kind, value) = match (kv.next(), kv.next()) {
346             (Some(kind), Some(value)) => (kind, value),
347             _ => return Err(format!("option must be of the form `kind=value`: {}", c)),
348         };
349         match kind {
350             "name" => name = value,
351             _ => return Err(format!("unrecognized option: {}", kind)),
352         }
353     }
354 
355     Ok((name.to_string(), path))
356 }
357 
358 #[derive(FromArgs)]
359 #[argh(subcommand, name = "wl")]
360 /// Wayland device
361 pub struct Options {
362     #[argh(option, arg_name = "PATH")]
363     /// path to bind a listening vhost-user socket
364     socket: String,
365     #[argh(option, from_str_fn(parse_wayland_sock), arg_name = "PATH[,name=NAME]")]
366     /// path to one or more Wayland sockets. The unnamed socket is used for
367     /// displaying virtual screens while the named ones are used for IPC
368     wayland_sock: Vec<(String, PathBuf)>,
369     #[argh(option, arg_name = "PATH")]
370     /// path to the GPU resource bridge
371     resource_bridge: Option<String>,
372 }
373 
374 /// Starts a vhost-user wayland device.
375 /// Returns an error if the given `args` is invalid or the device fails to run.
run_wl_device(opts: Options) -> anyhow::Result<()>376 pub fn run_wl_device(opts: Options) -> anyhow::Result<()> {
377     let Options {
378         wayland_sock,
379         socket,
380         resource_bridge,
381     } = opts;
382 
383     let wayland_paths: BTreeMap<_, _> = wayland_sock.into_iter().collect();
384 
385     let resource_bridge = resource_bridge
386         .map(|p| -> anyhow::Result<Tube> {
387             let deadline = Instant::now() + Duration::from_secs(5);
388             loop {
389                 match UnixSeqpacket::connect(&p) {
390                     Ok(s) => return Ok(Tube::new_from_unix_seqpacket(s).unwrap()),
391                     Err(e) => {
392                         if Instant::now() < deadline {
393                             thread::sleep(Duration::from_millis(50));
394                         } else {
395                             return Err(anyhow::Error::new(e));
396                         }
397                     }
398                 }
399             }
400         })
401         .transpose()
402         .context("failed to connect to resource bridge socket")?;
403 
404     let ex = Executor::new().context("failed to create executor")?;
405 
406     let listener = VhostUserListener::new_socket(&socket, None)?;
407 
408     let backend = WlBackend::new(&ex, wayland_paths, resource_bridge);
409     // run_until() returns an Result<Result<..>> which the ? operator lets us flatten.
410     ex.run_until(listener.run_backend(backend, &ex))?
411 }
412