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