devices/virtio/gpu/
mod.rs

1// Copyright 2018 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
5mod edid;
6mod parameters;
7mod protocol;
8mod snapshot;
9mod virtio_gpu;
10
11use std::cell::RefCell;
12use std::collections::BTreeMap;
13use std::io::Read;
14use std::path::PathBuf;
15use std::rc::Rc;
16use std::sync::atomic::AtomicBool;
17use std::sync::atomic::Ordering;
18use std::sync::mpsc;
19use std::sync::Arc;
20
21use ::snapshot::AnySnapshot;
22use anyhow::anyhow;
23use anyhow::Context;
24use base::custom_serde::deserialize_map_from_kv_vec;
25use base::custom_serde::serialize_map_as_kv_vec;
26use base::debug;
27use base::error;
28use base::info;
29#[cfg(any(target_os = "android", target_os = "linux"))]
30use base::linux::move_task_to_cgroup;
31use base::warn;
32use base::AsRawDescriptor;
33use base::Event;
34use base::EventToken;
35use base::RawDescriptor;
36use base::ReadNotifier;
37#[cfg(windows)]
38use base::RecvTube;
39use base::Result;
40use base::SafeDescriptor;
41use base::SendTube;
42use base::Tube;
43use base::VmEventType;
44use base::WaitContext;
45use base::WorkerThread;
46use data_model::*;
47pub use gpu_display::EventDevice;
48use gpu_display::*;
49use hypervisor::MemCacheType;
50pub use parameters::AudioDeviceMode;
51pub use parameters::GpuParameters;
52use rutabaga_gfx::*;
53use serde::Deserialize;
54use serde::Serialize;
55use sync::Mutex;
56pub use vm_control::gpu::DisplayMode as GpuDisplayMode;
57pub use vm_control::gpu::DisplayParameters as GpuDisplayParameters;
58use vm_control::gpu::GpuControlCommand;
59use vm_control::gpu::GpuControlResult;
60pub use vm_control::gpu::MouseMode as GpuMouseMode;
61pub use vm_control::gpu::DEFAULT_DISPLAY_HEIGHT;
62pub use vm_control::gpu::DEFAULT_DISPLAY_WIDTH;
63pub use vm_control::gpu::DEFAULT_REFRESH_RATE;
64#[cfg(windows)]
65use vm_control::ModifyWaitContext;
66use vm_memory::GuestAddress;
67use vm_memory::GuestMemory;
68use zerocopy::IntoBytes;
69
70pub use self::protocol::virtio_gpu_config;
71pub use self::protocol::VIRTIO_GPU_F_CONTEXT_INIT;
72pub use self::protocol::VIRTIO_GPU_F_CREATE_GUEST_HANDLE;
73pub use self::protocol::VIRTIO_GPU_F_EDID;
74pub use self::protocol::VIRTIO_GPU_F_RESOURCE_BLOB;
75pub use self::protocol::VIRTIO_GPU_F_RESOURCE_UUID;
76pub use self::protocol::VIRTIO_GPU_F_VIRGL;
77pub use self::protocol::VIRTIO_GPU_MAX_SCANOUTS;
78pub use self::protocol::VIRTIO_GPU_SHM_ID_HOST_VISIBLE;
79use self::protocol::*;
80use self::virtio_gpu::to_rutabaga_descriptor;
81pub use self::virtio_gpu::ProcessDisplayResult;
82use self::virtio_gpu::VirtioGpu;
83use self::virtio_gpu::VirtioGpuSnapshot;
84use super::copy_config;
85use super::resource_bridge::ResourceRequest;
86use super::DescriptorChain;
87use super::DeviceType;
88use super::Interrupt;
89use super::Queue;
90use super::Reader;
91use super::SharedMemoryMapper;
92use super::SharedMemoryPrepareType;
93use super::SharedMemoryRegion;
94use super::VirtioDevice;
95use super::Writer;
96use crate::PciAddress;
97
98// First queue is for virtio gpu commands. Second queue is for cursor commands, which we expect
99// there to be fewer of.
100const QUEUE_SIZES: &[u16] = &[512, 16];
101
102#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
103pub enum GpuMode {
104    #[default]
105    #[serde(rename = "2d", alias = "2D")]
106    Mode2D,
107    #[serde(rename = "virglrenderer", alias = "3d", alias = "3D")]
108    ModeVirglRenderer,
109    #[serde(rename = "gfxstream")]
110    ModeGfxstream,
111}
112
113#[derive(Clone, Debug, Serialize, Deserialize)]
114#[serde(rename_all = "kebab-case")]
115pub enum GpuWsi {
116    #[serde(alias = "vk")]
117    Vulkan,
118}
119
120#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
121pub struct VirtioScanoutBlobData {
122    pub width: u32,
123    pub height: u32,
124    pub drm_format: u32,
125    pub strides: [u32; 4],
126    pub offsets: [u32; 4],
127}
128
129#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
130enum VirtioGpuRing {
131    Global,
132    ContextSpecific { ctx_id: u32, ring_idx: u8 },
133}
134
135struct FenceDescriptor {
136    ring: VirtioGpuRing,
137    fence_id: u64,
138    desc_chain: DescriptorChain,
139    len: u32,
140}
141
142#[derive(Default)]
143pub struct FenceState {
144    descs: Vec<FenceDescriptor>,
145    completed_fences: BTreeMap<VirtioGpuRing, u64>,
146}
147
148#[derive(Serialize, Deserialize)]
149struct FenceStateSnapshot {
150    // Customize serialization to avoid errors when trying to use objects as keys in JSON
151    // dictionaries.
152    #[serde(
153        serialize_with = "serialize_map_as_kv_vec",
154        deserialize_with = "deserialize_map_from_kv_vec"
155    )]
156    completed_fences: BTreeMap<VirtioGpuRing, u64>,
157}
158
159impl FenceState {
160    fn snapshot(&self) -> FenceStateSnapshot {
161        assert!(self.descs.is_empty(), "can't snapshot with pending fences");
162        FenceStateSnapshot {
163            completed_fences: self.completed_fences.clone(),
164        }
165    }
166
167    fn restore(&mut self, snapshot: FenceStateSnapshot) {
168        assert!(self.descs.is_empty(), "can't restore activated device");
169        self.completed_fences = snapshot.completed_fences;
170    }
171}
172
173pub trait QueueReader {
174    fn pop(&self) -> Option<DescriptorChain>;
175    fn add_used(&self, desc_chain: DescriptorChain, len: u32);
176    fn signal_used(&self);
177}
178
179struct LocalQueueReader {
180    queue: RefCell<Queue>,
181}
182
183impl LocalQueueReader {
184    fn new(queue: Queue) -> Self {
185        Self {
186            queue: RefCell::new(queue),
187        }
188    }
189}
190
191impl QueueReader for LocalQueueReader {
192    fn pop(&self) -> Option<DescriptorChain> {
193        self.queue.borrow_mut().pop()
194    }
195
196    fn add_used(&self, desc_chain: DescriptorChain, len: u32) {
197        self.queue
198            .borrow_mut()
199            .add_used_with_bytes_written(desc_chain, len);
200    }
201
202    fn signal_used(&self) {
203        self.queue.borrow_mut().trigger_interrupt();
204    }
205}
206
207#[derive(Clone)]
208struct SharedQueueReader {
209    queue: Arc<Mutex<Queue>>,
210}
211
212impl SharedQueueReader {
213    fn new(queue: Queue) -> Self {
214        Self {
215            queue: Arc::new(Mutex::new(queue)),
216        }
217    }
218}
219
220impl QueueReader for SharedQueueReader {
221    fn pop(&self) -> Option<DescriptorChain> {
222        self.queue.lock().pop()
223    }
224
225    fn add_used(&self, desc_chain: DescriptorChain, len: u32) {
226        self.queue
227            .lock()
228            .add_used_with_bytes_written(desc_chain, len);
229    }
230
231    fn signal_used(&self) {
232        self.queue.lock().trigger_interrupt();
233    }
234}
235
236/// Initializes the virtio_gpu state tracker.
237fn build(
238    display_backends: &[DisplayBackend],
239    display_params: Vec<GpuDisplayParameters>,
240    display_event: Arc<AtomicBool>,
241    rutabaga: Rutabaga,
242    mapper: Arc<Mutex<Option<Box<dyn SharedMemoryMapper>>>>,
243    external_blob: bool,
244    fixed_blob_mapping: bool,
245    #[cfg(windows)] wndproc_thread: &mut Option<WindowProcedureThread>,
246    udmabuf: bool,
247    #[cfg(windows)] gpu_display_wait_descriptor_ctrl_wr: SendTube,
248    snapshot_scratch_directory: Option<PathBuf>,
249) -> Option<VirtioGpu> {
250    let mut display_opt = None;
251    for display_backend in display_backends {
252        match display_backend.build(
253            #[cfg(windows)]
254            wndproc_thread,
255            #[cfg(windows)]
256            gpu_display_wait_descriptor_ctrl_wr
257                .try_clone()
258                .expect("failed to clone wait context ctrl channel"),
259        ) {
260            Ok(c) => {
261                display_opt = Some(c);
262                break;
263            }
264            Err(e) => error!("failed to open display: {}", e),
265        };
266    }
267
268    let display = match display_opt {
269        Some(d) => d,
270        None => {
271            error!("failed to open any displays");
272            return None;
273        }
274    };
275
276    VirtioGpu::new(
277        display,
278        display_params,
279        display_event,
280        rutabaga,
281        mapper,
282        external_blob,
283        fixed_blob_mapping,
284        udmabuf,
285        snapshot_scratch_directory,
286    )
287}
288
289/// Resources used by the fence handler.
290pub struct FenceHandlerActivationResources<Q>
291where
292    Q: QueueReader + Send + Clone + 'static,
293{
294    pub mem: GuestMemory,
295    pub ctrl_queue: Q,
296}
297
298/// Create a handler that writes into the completed fence queue
299pub fn create_fence_handler<Q>(
300    fence_handler_resources: Arc<Mutex<Option<FenceHandlerActivationResources<Q>>>>,
301    fence_state: Arc<Mutex<FenceState>>,
302) -> RutabagaFenceHandler
303where
304    Q: QueueReader + Send + Clone + 'static,
305{
306    RutabagaFenceHandler::new(move |completed_fence: RutabagaFence| {
307        let mut signal = false;
308
309        if let Some(ref fence_handler_resources) = *fence_handler_resources.lock() {
310            // Limits the lifetime of `fence_state`:
311            {
312                let ring = match completed_fence.flags & VIRTIO_GPU_FLAG_INFO_RING_IDX {
313                    0 => VirtioGpuRing::Global,
314                    _ => VirtioGpuRing::ContextSpecific {
315                        ctx_id: completed_fence.ctx_id,
316                        ring_idx: completed_fence.ring_idx,
317                    },
318                };
319
320                let mut fence_state = fence_state.lock();
321                // TODO(dverkamp): use `drain_filter()` when it is stabilized
322                let mut i = 0;
323                while i < fence_state.descs.len() {
324                    if fence_state.descs[i].ring == ring
325                        && fence_state.descs[i].fence_id <= completed_fence.fence_id
326                    {
327                        let completed_desc = fence_state.descs.remove(i);
328                        fence_handler_resources
329                            .ctrl_queue
330                            .add_used(completed_desc.desc_chain, completed_desc.len);
331                        signal = true;
332                    } else {
333                        i += 1;
334                    }
335                }
336
337                // Update the last completed fence for this context
338                fence_state
339                    .completed_fences
340                    .insert(ring, completed_fence.fence_id);
341            }
342
343            if signal {
344                fence_handler_resources.ctrl_queue.signal_used();
345            }
346        }
347    })
348}
349
350pub struct ReturnDescriptor {
351    pub desc_chain: DescriptorChain,
352    pub len: u32,
353}
354
355pub struct Frontend {
356    fence_state: Arc<Mutex<FenceState>>,
357    virtio_gpu: VirtioGpu,
358}
359
360impl Frontend {
361    fn new(virtio_gpu: VirtioGpu, fence_state: Arc<Mutex<FenceState>>) -> Frontend {
362        Frontend {
363            fence_state,
364            virtio_gpu,
365        }
366    }
367
368    /// Returns the internal connection to the compositor and its associated state.
369    pub fn display(&mut self) -> &Rc<RefCell<GpuDisplay>> {
370        self.virtio_gpu.display()
371    }
372
373    /// Processes the internal `display` events and returns `true` if any display was closed.
374    pub fn process_display(&mut self) -> ProcessDisplayResult {
375        self.virtio_gpu.process_display()
376    }
377
378    /// Processes incoming requests on `resource_bridge`.
379    pub fn process_resource_bridge(&mut self, resource_bridge: &Tube) -> anyhow::Result<()> {
380        let response = match resource_bridge.recv() {
381            Ok(ResourceRequest::GetBuffer { id }) => self.virtio_gpu.export_resource(id),
382            Ok(ResourceRequest::GetFence { seqno }) => self.virtio_gpu.export_fence(seqno),
383            Err(e) => return Err(e).context("Error receiving resource bridge request"),
384        };
385
386        resource_bridge
387            .send(&response)
388            .context("Error sending resource bridge response")?;
389
390        Ok(())
391    }
392
393    /// Processes the GPU control command and returns the result with a bool indicating if the
394    /// GPU device's config needs to be updated.
395    pub fn process_gpu_control_command(&mut self, cmd: GpuControlCommand) -> GpuControlResult {
396        self.virtio_gpu.process_gpu_control_command(cmd)
397    }
398
399    fn process_gpu_command(
400        &mut self,
401        mem: &GuestMemory,
402        cmd: GpuCommand,
403        reader: &mut Reader,
404    ) -> VirtioGpuResult {
405        self.virtio_gpu.force_ctx_0();
406
407        match cmd {
408            GpuCommand::GetDisplayInfo(_) => Ok(GpuResponse::OkDisplayInfo(
409                self.virtio_gpu.display_info().to_vec(),
410            )),
411            GpuCommand::ResourceCreate2d(info) => {
412                let resource_id = info.resource_id.to_native();
413
414                let resource_create_3d = ResourceCreate3D {
415                    target: RUTABAGA_PIPE_TEXTURE_2D,
416                    format: info.format.to_native(),
417                    bind: RUTABAGA_PIPE_BIND_RENDER_TARGET,
418                    width: info.width.to_native(),
419                    height: info.height.to_native(),
420                    depth: 1,
421                    array_size: 1,
422                    last_level: 0,
423                    nr_samples: 0,
424                    flags: 0,
425                };
426
427                self.virtio_gpu
428                    .resource_create_3d(resource_id, resource_create_3d)
429            }
430            GpuCommand::ResourceUnref(info) => {
431                self.virtio_gpu.unref_resource(info.resource_id.to_native())
432            }
433            GpuCommand::SetScanout(info) => self.virtio_gpu.set_scanout(
434                info.r,
435                info.scanout_id.to_native(),
436                info.resource_id.to_native(),
437                None,
438            ),
439            GpuCommand::ResourceFlush(info) => {
440                self.virtio_gpu.flush_resource(info.resource_id.to_native())
441            }
442            GpuCommand::TransferToHost2d(info) => {
443                let resource_id = info.resource_id.to_native();
444                let transfer = Transfer3D::new_2d(
445                    info.r.x.to_native(),
446                    info.r.y.to_native(),
447                    info.r.width.to_native(),
448                    info.r.height.to_native(),
449                    info.offset.to_native(),
450                );
451                self.virtio_gpu.transfer_write(0, resource_id, transfer)
452            }
453            GpuCommand::ResourceAttachBacking(info) => {
454                let available_bytes = reader.available_bytes();
455                if available_bytes != 0 {
456                    let entry_count = info.nr_entries.to_native() as usize;
457                    let mut vecs = Vec::with_capacity(entry_count);
458                    for _ in 0..entry_count {
459                        match reader.read_obj::<virtio_gpu_mem_entry>() {
460                            Ok(entry) => {
461                                let addr = GuestAddress(entry.addr.to_native());
462                                let len = entry.length.to_native() as usize;
463                                vecs.push((addr, len))
464                            }
465                            Err(_) => return Err(GpuResponse::ErrUnspec),
466                        }
467                    }
468                    self.virtio_gpu
469                        .attach_backing(info.resource_id.to_native(), mem, vecs)
470                } else {
471                    error!("missing data for command {:?}", cmd);
472                    Err(GpuResponse::ErrUnspec)
473                }
474            }
475            GpuCommand::ResourceDetachBacking(info) => {
476                self.virtio_gpu.detach_backing(info.resource_id.to_native())
477            }
478            GpuCommand::UpdateCursor(info) => self.virtio_gpu.update_cursor(
479                info.resource_id.to_native(),
480                info.pos.scanout_id.to_native(),
481                info.pos.x.into(),
482                info.pos.y.into(),
483            ),
484            GpuCommand::MoveCursor(info) => self.virtio_gpu.move_cursor(
485                info.pos.scanout_id.to_native(),
486                info.pos.x.into(),
487                info.pos.y.into(),
488            ),
489            GpuCommand::ResourceAssignUuid(info) => {
490                let resource_id = info.resource_id.to_native();
491                self.virtio_gpu.resource_assign_uuid(resource_id)
492            }
493            GpuCommand::GetCapsetInfo(info) => self
494                .virtio_gpu
495                .get_capset_info(info.capset_index.to_native()),
496            GpuCommand::GetCapset(info) => self
497                .virtio_gpu
498                .get_capset(info.capset_id.to_native(), info.capset_version.to_native()),
499            GpuCommand::CtxCreate(info) => {
500                let context_name: Option<String> = String::from_utf8(info.debug_name.to_vec()).ok();
501                self.virtio_gpu.create_context(
502                    info.hdr.ctx_id.to_native(),
503                    info.context_init.to_native(),
504                    context_name.as_deref(),
505                )
506            }
507            GpuCommand::CtxDestroy(info) => {
508                self.virtio_gpu.destroy_context(info.hdr.ctx_id.to_native())
509            }
510            GpuCommand::CtxAttachResource(info) => self
511                .virtio_gpu
512                .context_attach_resource(info.hdr.ctx_id.to_native(), info.resource_id.to_native()),
513            GpuCommand::CtxDetachResource(info) => self
514                .virtio_gpu
515                .context_detach_resource(info.hdr.ctx_id.to_native(), info.resource_id.to_native()),
516            GpuCommand::ResourceCreate3d(info) => {
517                let resource_id = info.resource_id.to_native();
518                let resource_create_3d = ResourceCreate3D {
519                    target: info.target.to_native(),
520                    format: info.format.to_native(),
521                    bind: info.bind.to_native(),
522                    width: info.width.to_native(),
523                    height: info.height.to_native(),
524                    depth: info.depth.to_native(),
525                    array_size: info.array_size.to_native(),
526                    last_level: info.last_level.to_native(),
527                    nr_samples: info.nr_samples.to_native(),
528                    flags: info.flags.to_native(),
529                };
530
531                self.virtio_gpu
532                    .resource_create_3d(resource_id, resource_create_3d)
533            }
534            GpuCommand::TransferToHost3d(info) => {
535                let ctx_id = info.hdr.ctx_id.to_native();
536                let resource_id = info.resource_id.to_native();
537
538                let transfer = Transfer3D {
539                    x: info.box_.x.to_native(),
540                    y: info.box_.y.to_native(),
541                    z: info.box_.z.to_native(),
542                    w: info.box_.w.to_native(),
543                    h: info.box_.h.to_native(),
544                    d: info.box_.d.to_native(),
545                    level: info.level.to_native(),
546                    stride: info.stride.to_native(),
547                    layer_stride: info.layer_stride.to_native(),
548                    offset: info.offset.to_native(),
549                };
550
551                self.virtio_gpu
552                    .transfer_write(ctx_id, resource_id, transfer)
553            }
554            GpuCommand::TransferFromHost3d(info) => {
555                let ctx_id = info.hdr.ctx_id.to_native();
556                let resource_id = info.resource_id.to_native();
557
558                let transfer = Transfer3D {
559                    x: info.box_.x.to_native(),
560                    y: info.box_.y.to_native(),
561                    z: info.box_.z.to_native(),
562                    w: info.box_.w.to_native(),
563                    h: info.box_.h.to_native(),
564                    d: info.box_.d.to_native(),
565                    level: info.level.to_native(),
566                    stride: info.stride.to_native(),
567                    layer_stride: info.layer_stride.to_native(),
568                    offset: info.offset.to_native(),
569                };
570
571                self.virtio_gpu
572                    .transfer_read(ctx_id, resource_id, transfer, None)
573            }
574            GpuCommand::CmdSubmit3d(info) => {
575                if reader.available_bytes() != 0 {
576                    let cmd_size = info.size.to_native() as usize;
577                    let mut cmd_buf = vec![0; cmd_size];
578                    let ctx_id = info.hdr.ctx_id.to_native();
579
580                    if reader.read_exact(&mut cmd_buf[..]).is_ok() {
581                        self.virtio_gpu
582                            .submit_command(ctx_id, &mut cmd_buf[..], &[])
583                    } else {
584                        Err(GpuResponse::ErrInvalidParameter)
585                    }
586                } else {
587                    // Silently accept empty command buffers to allow for
588                    // benchmarking.
589                    Ok(GpuResponse::OkNoData)
590                }
591            }
592            GpuCommand::ResourceCreateBlob(info) => {
593                let resource_id = info.resource_id.to_native();
594                let ctx_id = info.hdr.ctx_id.to_native();
595
596                let resource_create_blob = ResourceCreateBlob {
597                    blob_mem: info.blob_mem.to_native(),
598                    blob_flags: info.blob_flags.to_native(),
599                    blob_id: info.blob_id.to_native(),
600                    size: info.size.to_native(),
601                };
602
603                let entry_count = info.nr_entries.to_native();
604                if reader.available_bytes() == 0 && entry_count > 0 {
605                    return Err(GpuResponse::ErrUnspec);
606                }
607
608                let mut vecs = Vec::with_capacity(entry_count as usize);
609                for _ in 0..entry_count {
610                    match reader.read_obj::<virtio_gpu_mem_entry>() {
611                        Ok(entry) => {
612                            let addr = GuestAddress(entry.addr.to_native());
613                            let len = entry.length.to_native() as usize;
614                            vecs.push((addr, len))
615                        }
616                        Err(_) => return Err(GpuResponse::ErrUnspec),
617                    }
618                }
619
620                self.virtio_gpu.resource_create_blob(
621                    ctx_id,
622                    resource_id,
623                    resource_create_blob,
624                    vecs,
625                    mem,
626                )
627            }
628            GpuCommand::SetScanoutBlob(info) => {
629                let scanout_id = info.scanout_id.to_native();
630                let resource_id = info.resource_id.to_native();
631                let virtio_gpu_format = info.format.to_native();
632                let width = info.width.to_native();
633                let height = info.height.to_native();
634                let mut strides: [u32; 4] = [0; 4];
635                let mut offsets: [u32; 4] = [0; 4];
636
637                // As of v4.19, virtio-gpu kms only really uses these formats.  If that changes,
638                // the following may have to change too.
639                let drm_format = match virtio_gpu_format {
640                    VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM => DrmFormat::new(b'X', b'R', b'2', b'4'),
641                    VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM => DrmFormat::new(b'A', b'R', b'2', b'4'),
642                    VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM => DrmFormat::new(b'A', b'B', b'2', b'4'),
643                    _ => {
644                        error!("unrecognized virtio-gpu format {}", virtio_gpu_format);
645                        return Err(GpuResponse::ErrUnspec);
646                    }
647                };
648
649                for plane_index in 0..PLANE_INFO_MAX_COUNT {
650                    offsets[plane_index] = info.offsets[plane_index].to_native();
651                    strides[plane_index] = info.strides[plane_index].to_native();
652                }
653
654                let scanout = VirtioScanoutBlobData {
655                    width,
656                    height,
657                    drm_format: drm_format.into(),
658                    strides,
659                    offsets,
660                };
661
662                self.virtio_gpu
663                    .set_scanout(info.r, scanout_id, resource_id, Some(scanout))
664            }
665            GpuCommand::ResourceMapBlob(info) => {
666                let resource_id = info.resource_id.to_native();
667                let offset = info.offset.to_native();
668                self.virtio_gpu
669                    .resource_map_blob(resource_id, offset)
670                    .inspect_err(|e| {
671                        // Log the details for triage.
672                        error!(
673                            "Failed to map blob, resource id {}, offset {}, error: {:#}",
674                            resource_id, offset, e
675                        );
676                    })
677                    .map_err(|e| match e.downcast::<GpuResponse>() {
678                        Ok(response) => response,
679                        Err(e) => {
680                            warn!(
681                                "No GPU response specified for {:?}, default to ErrUnspec",
682                                e
683                            );
684                            GpuResponse::ErrUnspec
685                        }
686                    })
687            }
688            GpuCommand::ResourceUnmapBlob(info) => {
689                let resource_id = info.resource_id.to_native();
690                self.virtio_gpu.resource_unmap_blob(resource_id)
691            }
692            GpuCommand::GetEdid(info) => self.virtio_gpu.get_edid(info.scanout.to_native()),
693        }
694    }
695
696    /// Processes virtio messages on `queue`.
697    pub fn process_queue(&mut self, mem: &GuestMemory, queue: &dyn QueueReader) -> bool {
698        let mut signal_used = false;
699        while let Some(desc) = queue.pop() {
700            if let Some(ret_desc) = self.process_descriptor(mem, desc) {
701                queue.add_used(ret_desc.desc_chain, ret_desc.len);
702                signal_used = true;
703            }
704        }
705
706        signal_used
707    }
708
709    fn process_descriptor(
710        &mut self,
711        mem: &GuestMemory,
712        mut desc_chain: DescriptorChain,
713    ) -> Option<ReturnDescriptor> {
714        let reader = &mut desc_chain.reader;
715        let writer = &mut desc_chain.writer;
716        let mut resp = Err(GpuResponse::ErrUnspec);
717        let mut gpu_cmd = None;
718        let mut len = 0;
719        match GpuCommand::decode(reader) {
720            Ok(cmd) => {
721                resp = self.process_gpu_command(mem, cmd, reader);
722                gpu_cmd = Some(cmd);
723            }
724            Err(e) => debug!("descriptor decode error: {}", e),
725        }
726
727        let mut gpu_response = match resp {
728            Ok(gpu_response) => gpu_response,
729            Err(gpu_response) => {
730                if let Some(gpu_cmd) = gpu_cmd {
731                    error!(
732                        "error processing gpu command {:?}: {:?}",
733                        gpu_cmd, gpu_response
734                    );
735                }
736                gpu_response
737            }
738        };
739
740        if writer.available_bytes() != 0 {
741            let mut fence_id = 0;
742            let mut ctx_id = 0;
743            let mut flags = 0;
744            let mut ring_idx = 0;
745            if let Some(cmd) = gpu_cmd {
746                let ctrl_hdr = cmd.ctrl_hdr();
747                if ctrl_hdr.flags.to_native() & VIRTIO_GPU_FLAG_FENCE != 0 {
748                    flags = ctrl_hdr.flags.to_native();
749                    fence_id = ctrl_hdr.fence_id.to_native();
750                    ctx_id = ctrl_hdr.ctx_id.to_native();
751                    ring_idx = ctrl_hdr.ring_idx;
752
753                    let fence = RutabagaFence {
754                        flags,
755                        fence_id,
756                        ctx_id,
757                        ring_idx,
758                    };
759                    gpu_response = match self.virtio_gpu.create_fence(fence) {
760                        Ok(_) => gpu_response,
761                        Err(fence_resp) => {
762                            warn!("create_fence {} -> {:?}", fence_id, fence_resp);
763                            fence_resp
764                        }
765                    };
766                }
767            }
768
769            // Prepare the response now, even if it is going to wait until
770            // fence is complete.
771            match gpu_response.encode(flags, fence_id, ctx_id, ring_idx, writer) {
772                Ok(l) => len = l,
773                Err(e) => debug!("ctrl queue response encode error: {}", e),
774            }
775
776            if flags & VIRTIO_GPU_FLAG_FENCE != 0 {
777                let ring = match flags & VIRTIO_GPU_FLAG_INFO_RING_IDX {
778                    0 => VirtioGpuRing::Global,
779                    _ => VirtioGpuRing::ContextSpecific { ctx_id, ring_idx },
780                };
781
782                // In case the fence is signaled immediately after creation, don't add a return
783                // FenceDescriptor.
784                let mut fence_state = self.fence_state.lock();
785                if fence_id > *fence_state.completed_fences.get(&ring).unwrap_or(&0) {
786                    fence_state.descs.push(FenceDescriptor {
787                        ring,
788                        fence_id,
789                        desc_chain,
790                        len,
791                    });
792
793                    return None;
794                }
795            }
796
797            // No fence (or already completed fence), respond now.
798        }
799        Some(ReturnDescriptor { desc_chain, len })
800    }
801
802    pub fn event_poll(&self) {
803        self.virtio_gpu.event_poll();
804    }
805}
806
807#[derive(EventToken, PartialEq, Eq, Clone, Copy, Debug)]
808enum WorkerToken {
809    CtrlQueue,
810    CursorQueue,
811    Display,
812    GpuControl,
813    Sleep,
814    Kill,
815    ResourceBridge {
816        index: usize,
817    },
818    VirtioGpuPoll,
819    #[cfg(windows)]
820    DisplayDescriptorRequest,
821}
822
823struct EventManager<'a> {
824    pub wait_ctx: WaitContext<WorkerToken>,
825    events: Vec<(&'a dyn AsRawDescriptor, WorkerToken)>,
826}
827
828impl<'a> EventManager<'a> {
829    pub fn new() -> Result<EventManager<'a>> {
830        Ok(EventManager {
831            wait_ctx: WaitContext::new()?,
832            events: vec![],
833        })
834    }
835
836    pub fn build_with(
837        triggers: &[(&'a dyn AsRawDescriptor, WorkerToken)],
838    ) -> Result<EventManager<'a>> {
839        let mut manager = EventManager::new()?;
840        manager.wait_ctx.add_many(triggers)?;
841
842        for (descriptor, token) in triggers {
843            manager.events.push((*descriptor, *token));
844        }
845        Ok(manager)
846    }
847
848    pub fn add(&mut self, descriptor: &'a dyn AsRawDescriptor, token: WorkerToken) -> Result<()> {
849        self.wait_ctx.add(descriptor, token)?;
850        self.events.push((descriptor, token));
851        Ok(())
852    }
853
854    pub fn delete(&mut self, token: WorkerToken) {
855        self.events.retain(|event| {
856            if event.1 == token {
857                self.wait_ctx.delete(event.0).ok();
858                return false;
859            }
860            true
861        });
862    }
863}
864
865#[derive(Serialize, Deserialize)]
866struct WorkerSnapshot {
867    fence_state_snapshot: FenceStateSnapshot,
868    virtio_gpu_snapshot: VirtioGpuSnapshot,
869}
870
871struct WorkerActivateRequest {
872    resources: GpuActivationResources,
873}
874
875enum WorkerRequest {
876    Activate(WorkerActivateRequest),
877    Suspend,
878    Snapshot,
879    Restore(WorkerSnapshot),
880}
881
882enum WorkerResponse {
883    Ok,
884    Suspend(GpuDeactivationResources),
885    Snapshot(WorkerSnapshot),
886}
887
888struct GpuActivationResources {
889    mem: GuestMemory,
890    interrupt: Interrupt,
891    ctrl_queue: SharedQueueReader,
892    cursor_queue: LocalQueueReader,
893}
894
895struct GpuDeactivationResources {
896    queues: Option<Vec<Queue>>,
897}
898
899struct Worker {
900    request_receiver: mpsc::Receiver<WorkerRequest>,
901    response_sender: mpsc::Sender<anyhow::Result<WorkerResponse>>,
902    exit_evt_wrtube: SendTube,
903    gpu_control_tube: Tube,
904    resource_bridges: ResourceBridges,
905    suspend_evt: Event,
906    kill_evt: Event,
907    state: Frontend,
908    fence_state: Arc<Mutex<FenceState>>,
909    fence_handler_resources: Arc<Mutex<Option<FenceHandlerActivationResources<SharedQueueReader>>>>,
910    #[cfg(windows)]
911    gpu_display_wait_descriptor_ctrl_rd: RecvTube,
912    activation_resources: Option<GpuActivationResources>,
913}
914
915#[derive(Copy, Clone)]
916enum WorkerStopReason {
917    Sleep,
918    Kill,
919}
920
921enum WorkerState {
922    Inactive,
923    Active,
924    Error,
925}
926
927fn build_rutabaga(
928    gpu_parameters: &GpuParameters,
929    display_params: &[GpuDisplayParameters],
930    rutabaga_component: RutabagaComponentType,
931    rutabaga_paths: Vec<RutabagaPath>,
932    rutabaga_server_descriptor: Option<RutabagaDescriptor>,
933    fence_handler: RutabagaFenceHandler,
934) -> RutabagaResult<Rutabaga> {
935    let (display_width, display_height) = display_params[0].get_virtual_display_size();
936
937    // Only allow virglrenderer to fork its own render server when explicitly requested.
938    // Caller can enforce its own restrictions (e.g. not allowed when sandboxed) and set the
939    // allow flag appropriately.
940    let use_render_server =
941        rutabaga_server_descriptor.is_some() || gpu_parameters.allow_implicit_render_server_exec;
942
943    let rutabaga_wsi = match gpu_parameters.wsi {
944        Some(GpuWsi::Vulkan) => RutabagaWsi::VulkanSwapchain,
945        _ => RutabagaWsi::Surfaceless,
946    };
947
948    RutabagaBuilder::new(gpu_parameters.capset_mask, fence_handler)
949        .set_default_component(rutabaga_component)
950        .set_display_width(display_width)
951        .set_display_height(display_height)
952        .set_rutabaga_paths(Some(rutabaga_paths))
953        .set_use_egl(gpu_parameters.renderer_use_egl)
954        .set_use_gles(gpu_parameters.renderer_use_gles)
955        .set_use_surfaceless(gpu_parameters.renderer_use_surfaceless)
956        .set_use_vulkan(gpu_parameters.use_vulkan.unwrap_or_default())
957        .set_wsi(rutabaga_wsi)
958        .set_use_external_blob(gpu_parameters.external_blob)
959        .set_use_system_blob(gpu_parameters.system_blob)
960        .set_use_render_server(use_render_server)
961        .set_renderer_features(gpu_parameters.renderer_features.clone())
962        .set_server_descriptor(rutabaga_server_descriptor)
963        .build()
964}
965
966impl Worker {
967    fn new(
968        gpu_parameters: GpuParameters,
969        rutabaga_paths: Vec<RutabagaPath>,
970        rutabaga_component: RutabagaComponentType,
971        rutabaga_server_descriptor: Option<RutabagaDescriptor>,
972        display_backends: Vec<DisplayBackend>,
973        display_params: Vec<GpuDisplayParameters>,
974        display_event: Arc<AtomicBool>,
975        mapper: Arc<Mutex<Option<Box<dyn SharedMemoryMapper>>>>,
976        event_devices: Vec<EventDevice>,
977        external_blob: bool,
978        fixed_blob_mapping: bool,
979        udmabuf: bool,
980        request_receiver: mpsc::Receiver<WorkerRequest>,
981        response_sender: mpsc::Sender<anyhow::Result<WorkerResponse>>,
982        exit_evt_wrtube: SendTube,
983        gpu_control_tube: Tube,
984        resource_bridges: ResourceBridges,
985        suspend_evt: Event,
986        kill_evt: Event,
987        #[cfg(windows)] mut wndproc_thread: Option<WindowProcedureThread>,
988        #[cfg(windows)] gpu_display_wait_descriptor_ctrl_rd: RecvTube,
989        #[cfg(windows)] gpu_display_wait_descriptor_ctrl_wr: SendTube,
990        snapshot_scratch_directory: Option<PathBuf>,
991    ) -> anyhow::Result<Worker> {
992        let fence_state = Arc::new(Mutex::new(Default::default()));
993        let fence_handler_resources = Arc::new(Mutex::new(None));
994        let fence_handler =
995            create_fence_handler(fence_handler_resources.clone(), fence_state.clone());
996
997        let rutabaga = build_rutabaga(
998            &gpu_parameters,
999            &display_params,
1000            rutabaga_component,
1001            rutabaga_paths,
1002            rutabaga_server_descriptor,
1003            fence_handler,
1004        )?;
1005
1006        let mut virtio_gpu = build(
1007            &display_backends,
1008            display_params,
1009            display_event,
1010            rutabaga,
1011            mapper,
1012            external_blob,
1013            fixed_blob_mapping,
1014            #[cfg(windows)]
1015            &mut wndproc_thread,
1016            udmabuf,
1017            #[cfg(windows)]
1018            gpu_display_wait_descriptor_ctrl_wr,
1019            snapshot_scratch_directory,
1020        )
1021        .ok_or_else(|| anyhow!("failed to build virtio gpu"))?;
1022
1023        for event_device in event_devices {
1024            virtio_gpu
1025                .import_event_device(event_device)
1026                // We lost the `EventDevice`, so fail hard.
1027                .context("failed to import event device")?;
1028        }
1029
1030        Ok(Worker {
1031            request_receiver,
1032            response_sender,
1033            exit_evt_wrtube,
1034            gpu_control_tube,
1035            resource_bridges,
1036            suspend_evt,
1037            kill_evt,
1038            state: Frontend::new(virtio_gpu, fence_state.clone()),
1039            fence_state,
1040            fence_handler_resources,
1041            #[cfg(windows)]
1042            gpu_display_wait_descriptor_ctrl_rd,
1043            activation_resources: None,
1044        })
1045    }
1046
1047    fn run(&mut self) {
1048        // This loop effectively only runs while the worker is inactive. Once activated via
1049        // a `WorkerRequest::Activate`, the worker will remain in `run_until_sleep_or_exit()`
1050        // until suspended via `kill_evt` or `suspend_evt` being signaled.
1051        loop {
1052            let request = match self.request_receiver.recv() {
1053                Ok(r) => r,
1054                Err(_) => {
1055                    info!("virtio gpu worker connection ended, exiting.");
1056                    return;
1057                }
1058            };
1059
1060            match request {
1061                WorkerRequest::Activate(request) => {
1062                    let response = self.on_activate(request).map(|_| WorkerResponse::Ok);
1063                    self.response_sender
1064                        .send(response)
1065                        .expect("failed to send gpu worker response for activate");
1066
1067                    let stop_reason = self
1068                        .run_until_sleep_or_exit()
1069                        .expect("failed to run gpu worker processing");
1070
1071                    if let WorkerStopReason::Kill = stop_reason {
1072                        break;
1073                    }
1074                }
1075                WorkerRequest::Suspend => {
1076                    let response = self.on_suspend().map(WorkerResponse::Suspend);
1077                    self.response_sender
1078                        .send(response)
1079                        .expect("failed to send gpu worker response for suspend");
1080                }
1081                WorkerRequest::Snapshot => {
1082                    let response = self.on_snapshot().map(WorkerResponse::Snapshot);
1083                    self.response_sender
1084                        .send(response)
1085                        .expect("failed to send gpu worker response for snapshot");
1086                }
1087                WorkerRequest::Restore(snapshot) => {
1088                    let response = self.on_restore(snapshot).map(|_| WorkerResponse::Ok);
1089                    self.response_sender
1090                        .send(response)
1091                        .expect("failed to send gpu worker response for restore");
1092                }
1093            }
1094        }
1095    }
1096
1097    fn on_activate(&mut self, request: WorkerActivateRequest) -> anyhow::Result<()> {
1098        self.fence_handler_resources
1099            .lock()
1100            .replace(FenceHandlerActivationResources {
1101                mem: request.resources.mem.clone(),
1102                ctrl_queue: request.resources.ctrl_queue.clone(),
1103            });
1104
1105        self.state
1106            .virtio_gpu
1107            .resume(&request.resources.mem)
1108            .context("gpu worker failed to activate virtio frontend")?;
1109
1110        self.activation_resources = Some(request.resources);
1111
1112        Ok(())
1113    }
1114
1115    fn on_suspend(&mut self) -> anyhow::Result<GpuDeactivationResources> {
1116        self.state
1117            .virtio_gpu
1118            .suspend()
1119            .context("failed to suspend VirtioGpu")?;
1120
1121        self.fence_handler_resources.lock().take();
1122
1123        let queues = if let Some(activation_resources) = self.activation_resources.take() {
1124            Some(vec![
1125                match Arc::try_unwrap(activation_resources.ctrl_queue.queue) {
1126                    Ok(x) => x.into_inner(),
1127                    Err(_) => panic!("too many refs on ctrl_queue"),
1128                },
1129                activation_resources.cursor_queue.queue.into_inner(),
1130            ])
1131        } else {
1132            None
1133        };
1134
1135        Ok(GpuDeactivationResources { queues })
1136    }
1137
1138    fn on_snapshot(&mut self) -> anyhow::Result<WorkerSnapshot> {
1139        Ok(WorkerSnapshot {
1140            fence_state_snapshot: self.fence_state.lock().snapshot(),
1141            virtio_gpu_snapshot: self
1142                .state
1143                .virtio_gpu
1144                .snapshot()
1145                .context("failed to snapshot VirtioGpu")?,
1146        })
1147    }
1148
1149    fn on_restore(&mut self, snapshot: WorkerSnapshot) -> anyhow::Result<()> {
1150        self.fence_state
1151            .lock()
1152            .restore(snapshot.fence_state_snapshot);
1153
1154        self.state
1155            .virtio_gpu
1156            .restore(snapshot.virtio_gpu_snapshot)
1157            .context("failed to restore VirtioGpu")?;
1158
1159        Ok(())
1160    }
1161
1162    fn run_until_sleep_or_exit(&mut self) -> anyhow::Result<WorkerStopReason> {
1163        let activation_resources = self
1164            .activation_resources
1165            .as_ref()
1166            .context("virtio gpu worker missing activation resources")?;
1167
1168        let display_desc =
1169            SafeDescriptor::try_from(&*self.state.display().borrow() as &dyn AsRawDescriptor)
1170                .context("failed getting event descriptor for display")?;
1171
1172        let ctrl_evt = activation_resources
1173            .ctrl_queue
1174            .queue
1175            .lock()
1176            .event()
1177            .try_clone()
1178            .context("failed to clone queue event")?;
1179        let cursor_evt = activation_resources
1180            .cursor_queue
1181            .queue
1182            .borrow()
1183            .event()
1184            .try_clone()
1185            .context("failed to clone queue event")?;
1186
1187        let mut event_manager = EventManager::build_with(&[
1188            (&ctrl_evt, WorkerToken::CtrlQueue),
1189            (&cursor_evt, WorkerToken::CursorQueue),
1190            (&display_desc, WorkerToken::Display),
1191            (
1192                self.gpu_control_tube.get_read_notifier(),
1193                WorkerToken::GpuControl,
1194            ),
1195            (&self.suspend_evt, WorkerToken::Sleep),
1196            (&self.kill_evt, WorkerToken::Kill),
1197            #[cfg(windows)]
1198            (
1199                self.gpu_display_wait_descriptor_ctrl_rd.get_read_notifier(),
1200                WorkerToken::DisplayDescriptorRequest,
1201            ),
1202        ])
1203        .context("failed creating gpu worker WaitContext")?;
1204
1205        let poll_desc: SafeDescriptor;
1206        if let Some(desc) = self.state.virtio_gpu.poll_descriptor() {
1207            poll_desc = desc;
1208            event_manager
1209                .add(&poll_desc, WorkerToken::VirtioGpuPoll)
1210                .context("failed adding poll event to WaitContext")?;
1211        }
1212
1213        self.resource_bridges
1214            .add_to_wait_context(&mut event_manager.wait_ctx);
1215
1216        // TODO(davidriley): The entire main loop processing is somewhat racey and incorrect with
1217        // respect to cursor vs control queue processing.  As both currently and originally
1218        // written, while the control queue is only processed/read from after the the cursor queue
1219        // is finished, the entire queue will be processed at that time.  The end effect of this
1220        // racyiness is that control queue descriptors that are issued after cursors descriptors
1221        // might be handled first instead of the other way around.  In practice, the cursor queue
1222        // isn't used so this isn't a huge issue.
1223
1224        loop {
1225            let events = event_manager
1226                .wait_ctx
1227                .wait()
1228                .context("failed polling for gpu worker events")?;
1229
1230            let mut signal_used_cursor = false;
1231            let mut signal_used_ctrl = false;
1232            let mut ctrl_available = false;
1233            let mut display_available = false;
1234            let mut needs_config_interrupt = false;
1235
1236            // Remove event triggers that have been hung-up to prevent unnecessary worker wake-ups
1237            // (see b/244486346#comment62 for context).
1238            for event in events.iter().filter(|e| e.is_hungup) {
1239                if event.token == WorkerToken::GpuControl {
1240                    return Ok(WorkerStopReason::Kill);
1241                }
1242                error!(
1243                    "unhandled virtio-gpu worker event hang-up detected: {:?}",
1244                    event.token
1245                );
1246                event_manager.delete(event.token);
1247            }
1248
1249            for event in events.iter().filter(|e| e.is_readable) {
1250                match event.token {
1251                    WorkerToken::CtrlQueue => {
1252                        let _ = ctrl_evt.wait();
1253                        // Set flag that control queue is available to be read, but defer reading
1254                        // until rest of the events are processed.
1255                        ctrl_available = true;
1256                    }
1257                    WorkerToken::CursorQueue => {
1258                        let _ = cursor_evt.wait();
1259                        if self.state.process_queue(
1260                            &activation_resources.mem,
1261                            &activation_resources.cursor_queue,
1262                        ) {
1263                            signal_used_cursor = true;
1264                        }
1265                    }
1266                    WorkerToken::Display => {
1267                        // We only need to process_display once-per-wake, regardless of how many
1268                        // WorkerToken::Display events are received.
1269                        display_available = true;
1270                    }
1271                    #[cfg(windows)]
1272                    WorkerToken::DisplayDescriptorRequest => {
1273                        if let Ok(req) = self
1274                            .gpu_display_wait_descriptor_ctrl_rd
1275                            .recv::<ModifyWaitContext>()
1276                        {
1277                            match req {
1278                                ModifyWaitContext::Add(desc) => {
1279                                    if let Err(e) =
1280                                        event_manager.wait_ctx.add(&desc, WorkerToken::Display)
1281                                    {
1282                                        error!(
1283                                            "failed to add extra descriptor from display \
1284                                             to GPU worker wait context: {:?}",
1285                                            e
1286                                        )
1287                                    }
1288                                }
1289                            }
1290                        } else {
1291                            error!("failed to receive ModifyWaitContext request.")
1292                        }
1293                    }
1294                    WorkerToken::GpuControl => {
1295                        let req = self
1296                            .gpu_control_tube
1297                            .recv()
1298                            .context("failed to recv from gpu control socket")?;
1299                        let resp = self.state.process_gpu_control_command(req);
1300
1301                        if let GpuControlResult::DisplaysUpdated = resp {
1302                            needs_config_interrupt = true;
1303                        }
1304
1305                        self.gpu_control_tube
1306                            .send(&resp)
1307                            .context("failed to send gpu control socket response")?;
1308                    }
1309                    WorkerToken::ResourceBridge { index } => {
1310                        self.resource_bridges.set_should_process(index);
1311                    }
1312                    WorkerToken::VirtioGpuPoll => {
1313                        self.state.event_poll();
1314                    }
1315                    WorkerToken::Sleep => {
1316                        return Ok(WorkerStopReason::Sleep);
1317                    }
1318                    WorkerToken::Kill => {
1319                        return Ok(WorkerStopReason::Kill);
1320                    }
1321                }
1322            }
1323
1324            if display_available {
1325                match self.state.process_display() {
1326                    ProcessDisplayResult::CloseRequested => {
1327                        let _ = self.exit_evt_wrtube.send::<VmEventType>(&VmEventType::Exit);
1328                    }
1329                    ProcessDisplayResult::Error(_e) => {
1330                        base::error!("Display processing failed, disabling display event handler.");
1331                        event_manager.delete(WorkerToken::Display);
1332                    }
1333                    ProcessDisplayResult::Success => (),
1334                };
1335            }
1336
1337            if ctrl_available
1338                && self
1339                    .state
1340                    .process_queue(&activation_resources.mem, &activation_resources.ctrl_queue)
1341            {
1342                signal_used_ctrl = true;
1343            }
1344
1345            // Process the entire control queue before the resource bridge in case a resource is
1346            // created or destroyed by the control queue. Processing the resource bridge first may
1347            // lead to a race condition.
1348            // TODO(davidriley): This is still inherently racey if both the control queue request
1349            // and the resource bridge request come in at the same time after the control queue is
1350            // processed above and before the corresponding bridge is processed below.
1351            self.resource_bridges
1352                .process_resource_bridges(&mut self.state, &mut event_manager.wait_ctx);
1353
1354            if signal_used_ctrl {
1355                activation_resources.ctrl_queue.signal_used();
1356            }
1357
1358            if signal_used_cursor {
1359                activation_resources.cursor_queue.signal_used();
1360            }
1361
1362            if needs_config_interrupt {
1363                activation_resources.interrupt.signal_config_changed();
1364            }
1365        }
1366    }
1367}
1368
1369/// Indicates a backend that should be tried for the gpu to use for display.
1370///
1371/// Several instances of this enum are used in an ordered list to give the gpu device many backends
1372/// to use as fallbacks in case some do not work.
1373#[derive(Clone)]
1374pub enum DisplayBackend {
1375    #[cfg(any(target_os = "android", target_os = "linux"))]
1376    /// Use the wayland backend with the given socket path if given.
1377    Wayland(Option<PathBuf>),
1378    #[cfg(any(target_os = "android", target_os = "linux"))]
1379    /// Open a connection to the X server at the given display if given.
1380    X(Option<String>),
1381    /// Emulate a display without actually displaying it.
1382    Stub,
1383    #[cfg(windows)]
1384    /// Open a window using WinAPI.
1385    WinApi,
1386    #[cfg(feature = "android_display")]
1387    /// The display buffer is backed by an Android surface. The surface is set via an AIDL service
1388    /// that the backend hosts. Currently, the AIDL service is registered to the service manager
1389    /// using the name given here. The entity holding the surface is expected to locate the service
1390    /// via this name, and pass the surface to it.
1391    Android(String),
1392}
1393
1394impl DisplayBackend {
1395    fn build(
1396        &self,
1397        #[cfg(windows)] wndproc_thread: &mut Option<WindowProcedureThread>,
1398        #[cfg(windows)] gpu_display_wait_descriptor_ctrl: SendTube,
1399    ) -> std::result::Result<GpuDisplay, GpuDisplayError> {
1400        match self {
1401            #[cfg(any(target_os = "android", target_os = "linux"))]
1402            DisplayBackend::Wayland(path) => GpuDisplay::open_wayland(path.as_ref()),
1403            #[cfg(any(target_os = "android", target_os = "linux"))]
1404            DisplayBackend::X(display) => GpuDisplay::open_x(display.as_deref()),
1405            DisplayBackend::Stub => GpuDisplay::open_stub(),
1406            #[cfg(windows)]
1407            DisplayBackend::WinApi => match wndproc_thread.take() {
1408                Some(wndproc_thread) => GpuDisplay::open_winapi(
1409                    wndproc_thread,
1410                    /* win_metrics= */ None,
1411                    gpu_display_wait_descriptor_ctrl,
1412                    None,
1413                ),
1414                None => {
1415                    error!("wndproc_thread is none");
1416                    Err(GpuDisplayError::Allocate)
1417                }
1418            },
1419            #[cfg(feature = "android_display")]
1420            DisplayBackend::Android(service_name) => GpuDisplay::open_android(service_name),
1421        }
1422    }
1423}
1424
1425pub struct Gpu {
1426    exit_evt_wrtube: SendTube,
1427    pub gpu_control_tube: Option<Tube>,
1428    mapper: Arc<Mutex<Option<Box<dyn SharedMemoryMapper>>>>,
1429    resource_bridges: Option<ResourceBridges>,
1430    event_devices: Option<Vec<EventDevice>>,
1431    worker_suspend_evt: Option<Event>,
1432    worker_request_sender: Option<mpsc::Sender<WorkerRequest>>,
1433    worker_response_receiver: Option<mpsc::Receiver<anyhow::Result<WorkerResponse>>>,
1434    worker_state: WorkerState,
1435    worker_thread: Option<WorkerThread<()>>,
1436    display_backends: Vec<DisplayBackend>,
1437    display_params: Vec<GpuDisplayParameters>,
1438    display_event: Arc<AtomicBool>,
1439    gpu_parameters: GpuParameters,
1440    rutabaga_paths: Vec<RutabagaPath>,
1441    pci_address: Option<PciAddress>,
1442    pci_bar_size: u64,
1443    external_blob: bool,
1444    fixed_blob_mapping: bool,
1445    rutabaga_component: RutabagaComponentType,
1446    #[cfg(windows)]
1447    wndproc_thread: Option<WindowProcedureThread>,
1448    base_features: u64,
1449    udmabuf: bool,
1450    rutabaga_server_descriptor: Option<SafeDescriptor>,
1451    #[cfg(windows)]
1452    /// Because the Windows GpuDisplay can't expose an epollfd, it has to inform the GPU worker
1453    /// which descriptors to add to its wait context. That's what this Tube is used for (it is
1454    /// provided to each display backend.
1455    gpu_display_wait_descriptor_ctrl_wr: SendTube,
1456    #[cfg(windows)]
1457    /// The GPU worker uses this Tube to receive the descriptors that should be added to its wait
1458    /// context.
1459    gpu_display_wait_descriptor_ctrl_rd: Option<RecvTube>,
1460    capset_mask: u64,
1461    #[cfg(any(target_os = "android", target_os = "linux"))]
1462    gpu_cgroup_path: Option<PathBuf>,
1463    snapshot_scratch_directory: Option<PathBuf>,
1464}
1465
1466impl Gpu {
1467    pub fn new(
1468        exit_evt_wrtube: SendTube,
1469        gpu_control_tube: Tube,
1470        resource_bridges: Vec<Tube>,
1471        display_backends: Vec<DisplayBackend>,
1472        gpu_parameters: &GpuParameters,
1473        rutabaga_server_descriptor: Option<SafeDescriptor>,
1474        event_devices: Vec<EventDevice>,
1475        base_features: u64,
1476        paths: &BTreeMap<String, PathBuf>,
1477        #[cfg(windows)] wndproc_thread: WindowProcedureThread,
1478        #[cfg(any(target_os = "android", target_os = "linux"))] gpu_cgroup_path: Option<&PathBuf>,
1479    ) -> Gpu {
1480        let mut display_params = gpu_parameters.display_params.clone();
1481        if display_params.is_empty() {
1482            display_params.push(Default::default());
1483        }
1484
1485        let mut rutabaga_paths: Vec<RutabagaPath> = Vec::new();
1486        for (name, path) in paths {
1487            match &name[..] {
1488                "" => rutabaga_paths.push(RutabagaPath {
1489                    path: path.clone(),
1490                    path_type: RUTABAGA_PATH_TYPE_WAYLAND,
1491                }),
1492                _ => error!("unknown rutabaga path"),
1493            }
1494        }
1495
1496        let component = match gpu_parameters.mode {
1497            GpuMode::Mode2D => RutabagaComponentType::Rutabaga2D,
1498            GpuMode::ModeVirglRenderer => RutabagaComponentType::VirglRenderer,
1499            GpuMode::ModeGfxstream => RutabagaComponentType::Gfxstream,
1500        };
1501
1502        #[cfg(windows)]
1503        let (gpu_display_wait_descriptor_ctrl_wr, gpu_display_wait_descriptor_ctrl_rd) =
1504            Tube::directional_pair().expect("failed to create wait descriptor control pair.");
1505
1506        Gpu {
1507            exit_evt_wrtube,
1508            gpu_control_tube: Some(gpu_control_tube),
1509            mapper: Arc::new(Mutex::new(None)),
1510            resource_bridges: Some(ResourceBridges::new(resource_bridges)),
1511            event_devices: Some(event_devices),
1512            worker_request_sender: None,
1513            worker_response_receiver: None,
1514            worker_suspend_evt: None,
1515            worker_state: WorkerState::Inactive,
1516            worker_thread: None,
1517            display_backends,
1518            display_params,
1519            display_event: Arc::new(AtomicBool::new(false)),
1520            gpu_parameters: gpu_parameters.clone(),
1521            rutabaga_paths,
1522            pci_address: gpu_parameters.pci_address,
1523            pci_bar_size: gpu_parameters.pci_bar_size,
1524            external_blob: gpu_parameters.external_blob,
1525            fixed_blob_mapping: gpu_parameters.fixed_blob_mapping,
1526            rutabaga_component: component,
1527            #[cfg(windows)]
1528            wndproc_thread: Some(wndproc_thread),
1529            base_features,
1530            udmabuf: gpu_parameters.udmabuf,
1531            rutabaga_server_descriptor,
1532            #[cfg(windows)]
1533            gpu_display_wait_descriptor_ctrl_wr,
1534            #[cfg(windows)]
1535            gpu_display_wait_descriptor_ctrl_rd: Some(gpu_display_wait_descriptor_ctrl_rd),
1536            capset_mask: gpu_parameters.capset_mask,
1537            #[cfg(any(target_os = "android", target_os = "linux"))]
1538            gpu_cgroup_path: gpu_cgroup_path.cloned(),
1539            snapshot_scratch_directory: gpu_parameters.snapshot_scratch_path.clone(),
1540        }
1541    }
1542
1543    /// Initializes the internal device state so that it can begin processing virtqueues.
1544    ///
1545    /// Only used by vhost-user GPU.
1546    pub fn initialize_frontend(
1547        &mut self,
1548        fence_state: Arc<Mutex<FenceState>>,
1549        fence_handler: RutabagaFenceHandler,
1550        mapper: Arc<Mutex<Option<Box<dyn SharedMemoryMapper>>>>,
1551    ) -> Option<Frontend> {
1552        let rutabaga_server_descriptor = self.rutabaga_server_descriptor.as_ref().map(|d| {
1553            to_rutabaga_descriptor(d.try_clone().expect("failed to clone server descriptor"))
1554        });
1555
1556        let rutabaga = build_rutabaga(
1557            &self.gpu_parameters,
1558            &self.display_params,
1559            self.rutabaga_component,
1560            self.rutabaga_paths.clone(),
1561            rutabaga_server_descriptor,
1562            fence_handler,
1563        )
1564        .map_err(|e| error!("failed to build rutabaga {}", e))
1565        .ok()?;
1566
1567        let mut virtio_gpu = build(
1568            &self.display_backends,
1569            self.display_params.clone(),
1570            self.display_event.clone(),
1571            rutabaga,
1572            mapper,
1573            self.external_blob,
1574            self.fixed_blob_mapping,
1575            #[cfg(windows)]
1576            &mut self.wndproc_thread,
1577            self.udmabuf,
1578            #[cfg(windows)]
1579            self.gpu_display_wait_descriptor_ctrl_wr
1580                .try_clone()
1581                .expect("failed to clone wait context control channel"),
1582            self.snapshot_scratch_directory.clone(),
1583        )?;
1584
1585        for event_device in self.event_devices.take().expect("missing event_devices") {
1586            virtio_gpu
1587                .import_event_device(event_device)
1588                // We lost the `EventDevice`, so fail hard.
1589                .expect("failed to import event device");
1590        }
1591
1592        Some(Frontend::new(virtio_gpu, fence_state))
1593    }
1594
1595    // This is not invoked when running with vhost-user GPU.
1596    fn start_worker_thread(&mut self) {
1597        let suspend_evt = Event::new().unwrap();
1598        let suspend_evt_copy = suspend_evt
1599            .try_clone()
1600            .context("error cloning suspend event")
1601            .unwrap();
1602
1603        let exit_evt_wrtube = self
1604            .exit_evt_wrtube
1605            .try_clone()
1606            .context("error cloning exit tube")
1607            .unwrap();
1608
1609        let gpu_control_tube = self
1610            .gpu_control_tube
1611            .take()
1612            .context("gpu_control_tube is none")
1613            .unwrap();
1614
1615        let resource_bridges = self
1616            .resource_bridges
1617            .take()
1618            .context("resource_bridges is none")
1619            .unwrap();
1620
1621        let display_backends = self.display_backends.clone();
1622        let display_params = self.display_params.clone();
1623        let display_event = self.display_event.clone();
1624        let event_devices = self.event_devices.take().expect("missing event_devices");
1625        let external_blob = self.external_blob;
1626        let fixed_blob_mapping = self.fixed_blob_mapping;
1627        let udmabuf = self.udmabuf;
1628        let snapshot_scratch_directory = self.snapshot_scratch_directory.clone();
1629
1630        #[cfg(windows)]
1631        let mut wndproc_thread = self.wndproc_thread.take();
1632
1633        #[cfg(windows)]
1634        let gpu_display_wait_descriptor_ctrl_wr = self
1635            .gpu_display_wait_descriptor_ctrl_wr
1636            .try_clone()
1637            .expect("failed to clone wait context ctrl channel");
1638
1639        #[cfg(windows)]
1640        let gpu_display_wait_descriptor_ctrl_rd = self
1641            .gpu_display_wait_descriptor_ctrl_rd
1642            .take()
1643            .expect("failed to take gpu_display_wait_descriptor_ctrl_rd");
1644
1645        #[cfg(any(target_os = "android", target_os = "linux"))]
1646        let gpu_cgroup_path = self.gpu_cgroup_path.clone();
1647
1648        let mapper = Arc::clone(&self.mapper);
1649
1650        let gpu_parameters = self.gpu_parameters.clone();
1651        let rutabaga_paths = self.rutabaga_paths.clone();
1652        let rutabaga_component = self.rutabaga_component;
1653        let rutabaga_server_descriptor = self.rutabaga_server_descriptor.as_ref().map(|d| {
1654            to_rutabaga_descriptor(d.try_clone().expect("failed to clone server descriptor"))
1655        });
1656
1657        let (init_finished_tx, init_finished_rx) = mpsc::channel();
1658
1659        let (worker_request_sender, worker_request_receiver) = mpsc::channel();
1660        let (worker_response_sender, worker_response_receiver) = mpsc::channel();
1661
1662        let worker_thread = WorkerThread::start("v_gpu", move |kill_evt| {
1663            #[cfg(any(target_os = "android", target_os = "linux"))]
1664            if let Some(cgroup_path) = gpu_cgroup_path {
1665                move_task_to_cgroup(cgroup_path, base::gettid())
1666                    .expect("Failed to move v_gpu into requested cgroup");
1667            }
1668
1669            let mut worker = Worker::new(
1670                gpu_parameters,
1671                rutabaga_paths,
1672                rutabaga_component,
1673                rutabaga_server_descriptor,
1674                display_backends,
1675                display_params,
1676                display_event,
1677                mapper,
1678                event_devices,
1679                external_blob,
1680                fixed_blob_mapping,
1681                udmabuf,
1682                worker_request_receiver,
1683                worker_response_sender,
1684                exit_evt_wrtube,
1685                gpu_control_tube,
1686                resource_bridges,
1687                suspend_evt_copy,
1688                kill_evt,
1689                #[cfg(windows)]
1690                wndproc_thread,
1691                #[cfg(windows)]
1692                gpu_display_wait_descriptor_ctrl_rd,
1693                #[cfg(windows)]
1694                gpu_display_wait_descriptor_ctrl_wr,
1695                snapshot_scratch_directory,
1696            )
1697            .expect("Failed to create virtio gpu worker thread");
1698
1699            // Tell the parent thread that the init phase is complete.
1700            let _ = init_finished_tx.send(());
1701
1702            worker.run()
1703        });
1704
1705        self.worker_request_sender = Some(worker_request_sender);
1706        self.worker_response_receiver = Some(worker_response_receiver);
1707        self.worker_suspend_evt = Some(suspend_evt);
1708        self.worker_state = WorkerState::Inactive;
1709        self.worker_thread = Some(worker_thread);
1710
1711        match init_finished_rx.recv() {
1712            Ok(()) => {}
1713            Err(mpsc::RecvError) => panic!("virtio-gpu worker thread init failed"),
1714        }
1715    }
1716
1717    fn stop_worker_thread(&mut self) {
1718        self.worker_request_sender.take();
1719        self.worker_response_receiver.take();
1720        self.worker_suspend_evt.take();
1721        if let Some(worker_thread) = self.worker_thread.take() {
1722            worker_thread.stop();
1723        }
1724    }
1725
1726    fn get_config(&self) -> virtio_gpu_config {
1727        let mut events_read = 0;
1728
1729        if self.display_event.load(Ordering::Relaxed) {
1730            events_read |= VIRTIO_GPU_EVENT_DISPLAY;
1731        }
1732
1733        let num_capsets = match self.capset_mask {
1734            0 => match self.rutabaga_component {
1735                RutabagaComponentType::Rutabaga2D => 0,
1736                RutabagaComponentType::VirglRenderer => 3,
1737                RutabagaComponentType::Gfxstream => 1,
1738                _ => unimplemented!(),
1739            },
1740            _ => self.capset_mask.count_ones(),
1741        };
1742
1743        virtio_gpu_config {
1744            events_read: Le32::from(events_read),
1745            events_clear: Le32::from(0),
1746            num_scanouts: Le32::from(VIRTIO_GPU_MAX_SCANOUTS as u32),
1747            num_capsets: Le32::from(num_capsets),
1748        }
1749    }
1750
1751    /// Send a request to exit the process to VMM.
1752    pub fn send_exit_evt(&self) -> anyhow::Result<()> {
1753        self.exit_evt_wrtube
1754            .send::<VmEventType>(&VmEventType::Exit)
1755            .context("failed to send exit event")
1756    }
1757}
1758
1759impl VirtioDevice for Gpu {
1760    fn keep_rds(&self) -> Vec<RawDescriptor> {
1761        let mut keep_rds = Vec::new();
1762
1763        // To find the RawDescriptor associated with stdout and stderr on Windows is difficult.
1764        // Resource bridges are used only for Wayland displays. There is also no meaningful way
1765        // casting the underlying DMA buffer wrapped in File to a copyable RawDescriptor.
1766        // TODO(davidriley): Remove once virgl has another path to include
1767        // debugging logs.
1768        #[cfg(any(target_os = "android", target_os = "linux"))]
1769        if cfg!(debug_assertions) {
1770            keep_rds.push(libc::STDOUT_FILENO);
1771            keep_rds.push(libc::STDERR_FILENO);
1772        }
1773
1774        if let Some(ref mapper) = *self.mapper.lock() {
1775            if let Some(descriptor) = mapper.as_raw_descriptor() {
1776                keep_rds.push(descriptor);
1777            }
1778        }
1779
1780        if let Some(ref rutabaga_server_descriptor) = self.rutabaga_server_descriptor {
1781            keep_rds.push(rutabaga_server_descriptor.as_raw_descriptor());
1782        }
1783
1784        keep_rds.push(self.exit_evt_wrtube.as_raw_descriptor());
1785
1786        if let Some(gpu_control_tube) = &self.gpu_control_tube {
1787            keep_rds.push(gpu_control_tube.as_raw_descriptor());
1788        }
1789
1790        if let Some(resource_bridges) = &self.resource_bridges {
1791            resource_bridges.append_raw_descriptors(&mut keep_rds);
1792        }
1793
1794        for event_device in self.event_devices.iter().flatten() {
1795            keep_rds.push(event_device.as_raw_descriptor());
1796        }
1797
1798        keep_rds
1799    }
1800
1801    fn device_type(&self) -> DeviceType {
1802        DeviceType::Gpu
1803    }
1804
1805    fn queue_max_sizes(&self) -> &[u16] {
1806        QUEUE_SIZES
1807    }
1808
1809    fn features(&self) -> u64 {
1810        let mut virtio_gpu_features = 1 << VIRTIO_GPU_F_EDID | 1 << VIRTIO_GPU_F_RESOURCE_BLOB;
1811
1812        // If a non-2D component is specified, enable 3D features.  It is possible to run display
1813        // contexts without 3D backend (i.e, gfxstream / virglrender), so check for that too.
1814        if self.rutabaga_component != RutabagaComponentType::Rutabaga2D || self.capset_mask != 0 {
1815            virtio_gpu_features |= 1 << VIRTIO_GPU_F_VIRGL
1816                | 1 << VIRTIO_GPU_F_RESOURCE_UUID
1817                | 1 << VIRTIO_GPU_F_CONTEXT_INIT;
1818
1819            if self.udmabuf {
1820                virtio_gpu_features |= 1 << VIRTIO_GPU_F_CREATE_GUEST_HANDLE;
1821            }
1822        }
1823
1824        self.base_features | virtio_gpu_features
1825    }
1826
1827    fn ack_features(&mut self, value: u64) {
1828        let _ = value;
1829    }
1830
1831    fn read_config(&self, offset: u64, data: &mut [u8]) {
1832        copy_config(data, 0, self.get_config().as_bytes(), offset);
1833    }
1834
1835    fn write_config(&mut self, offset: u64, data: &[u8]) {
1836        let mut cfg = self.get_config();
1837        copy_config(cfg.as_mut_bytes(), offset, data, 0);
1838        if (cfg.events_clear.to_native() & VIRTIO_GPU_EVENT_DISPLAY) != 0 {
1839            self.display_event.store(false, Ordering::Relaxed);
1840        }
1841    }
1842
1843    fn on_device_sandboxed(&mut self) {
1844        // Unlike most Virtio devices which start their worker thread in activate(),
1845        // the Gpu's worker thread is started earlier here so that rutabaga and the
1846        // underlying render server have a chance to initialize before the guest OS
1847        // starts. This is needed because the Virtio GPU kernel module has a timeout
1848        // for some calls during initialization and some host GPU drivers have been
1849        // observed to be extremely slow to initialize on fresh GCE instances. The
1850        // entire worker thread is started here (as opposed to just initializing
1851        // rutabaga and the underlying render server) as OpenGL based renderers may
1852        // expect to be initialized on the same thread that later processes commands.
1853        self.start_worker_thread();
1854    }
1855
1856    fn activate(
1857        &mut self,
1858        mem: GuestMemory,
1859        interrupt: Interrupt,
1860        mut queues: BTreeMap<usize, Queue>,
1861    ) -> anyhow::Result<()> {
1862        if queues.len() != QUEUE_SIZES.len() {
1863            return Err(anyhow!(
1864                "expected {} queues, got {}",
1865                QUEUE_SIZES.len(),
1866                queues.len()
1867            ));
1868        }
1869
1870        let ctrl_queue = SharedQueueReader::new(queues.remove(&0).unwrap());
1871        let cursor_queue = LocalQueueReader::new(queues.remove(&1).unwrap());
1872
1873        self.worker_request_sender
1874            .as_ref()
1875            .context("worker thread missing on activate?")?
1876            .send(WorkerRequest::Activate(WorkerActivateRequest {
1877                resources: GpuActivationResources {
1878                    mem,
1879                    interrupt,
1880                    ctrl_queue,
1881                    cursor_queue,
1882                },
1883            }))
1884            .map_err(|e| anyhow!("failed to send virtio gpu worker activate request: {:?}", e))?;
1885
1886        self.worker_response_receiver
1887            .as_ref()
1888            .context("worker thread missing on activate?")?
1889            .recv()
1890            .inspect(|_| self.worker_state = WorkerState::Active)
1891            .inspect_err(|_| self.worker_state = WorkerState::Error)
1892            .context("failed to receive response for virtio gpu worker resume request")??;
1893
1894        Ok(())
1895    }
1896
1897    fn pci_address(&self) -> Option<PciAddress> {
1898        self.pci_address
1899    }
1900
1901    fn get_shared_memory_region(&self) -> Option<SharedMemoryRegion> {
1902        Some(SharedMemoryRegion {
1903            id: VIRTIO_GPU_SHM_ID_HOST_VISIBLE,
1904            length: self.pci_bar_size,
1905        })
1906    }
1907
1908    fn set_shared_memory_mapper(&mut self, mapper: Box<dyn SharedMemoryMapper>) {
1909        self.mapper.lock().replace(mapper);
1910    }
1911
1912    fn expose_shmem_descriptors_with_viommu(&self) -> bool {
1913        // TODO(b/323368701): integrate with fixed_blob_mapping so this can always return true.
1914        !self.fixed_blob_mapping
1915    }
1916
1917    fn get_shared_memory_prepare_type(&mut self) -> SharedMemoryPrepareType {
1918        if self.fixed_blob_mapping {
1919            let cache_type = if cfg!(feature = "noncoherent-dma") {
1920                MemCacheType::CacheNonCoherent
1921            } else {
1922                MemCacheType::CacheCoherent
1923            };
1924            SharedMemoryPrepareType::SingleMappingOnFirst(cache_type)
1925        } else {
1926            SharedMemoryPrepareType::DynamicPerMapping
1927        }
1928    }
1929
1930    // Notes on sleep/wake/snapshot/restore functionality.
1931    //
1932    //   * Only 2d mode is supported so far.
1933    //   * We only snapshot the state relevant to the virtio-gpu 2d mode protocol (i.e. scanouts,
1934    //     resources, fences).
1935    //   * The GpuDisplay is recreated from scratch, we don't want to snapshot the state of a
1936    //     Wayland socket (for example).
1937    //   * No state about pending virtio requests needs to be snapshotted because the 2d backend
1938    //     completes them synchronously.
1939    fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> {
1940        match self.worker_state {
1941            WorkerState::Error => {
1942                return Err(anyhow!(
1943                    "failed to sleep virtio gpu worker which is in error state"
1944                ));
1945            }
1946            WorkerState::Inactive => {
1947                return Ok(None);
1948            }
1949            _ => (),
1950        };
1951
1952        if let (
1953            Some(worker_request_sender),
1954            Some(worker_response_receiver),
1955            Some(worker_suspend_evt),
1956        ) = (
1957            &self.worker_request_sender,
1958            &self.worker_response_receiver,
1959            &self.worker_suspend_evt,
1960        ) {
1961            worker_request_sender
1962                .send(WorkerRequest::Suspend)
1963                .map_err(|e| {
1964                    anyhow!(
1965                        "failed to send suspend request to virtio gpu worker: {:?}",
1966                        e
1967                    )
1968                })?;
1969
1970            worker_suspend_evt
1971                .signal()
1972                .context("failed to signal virtio gpu worker suspend event")?;
1973
1974            let response = worker_response_receiver
1975                .recv()
1976                .inspect(|_| self.worker_state = WorkerState::Inactive)
1977                .inspect_err(|_| self.worker_state = WorkerState::Error)
1978                .context("failed to receive response for virtio gpu worker suspend request")??;
1979
1980            worker_suspend_evt
1981                .reset()
1982                .context("failed to reset virtio gpu worker suspend event")?;
1983
1984            match response {
1985                WorkerResponse::Suspend(deactivation_resources) => Ok(deactivation_resources
1986                    .queues
1987                    .map(|q| q.into_iter().enumerate().collect())),
1988                _ => {
1989                    panic!("unexpected response from virtio gpu worker sleep request");
1990                }
1991            }
1992        } else {
1993            Err(anyhow!("virtio gpu worker not available for sleep"))
1994        }
1995    }
1996
1997    fn virtio_wake(
1998        &mut self,
1999        queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>,
2000    ) -> anyhow::Result<()> {
2001        match self.worker_state {
2002            WorkerState::Error => {
2003                return Err(anyhow!(
2004                    "failed to wake virtio gpu worker which is in error state"
2005                ));
2006            }
2007            WorkerState::Active => {
2008                return Ok(());
2009            }
2010            _ => (),
2011        };
2012
2013        match queues_state {
2014            None => Ok(()),
2015            Some((mem, interrupt, queues)) => {
2016                // TODO(khei): activate is just what we want at the moment, but we should probably
2017                // move it into a "start workers" function to make it obvious that it isn't
2018                // strictly used for activate events.
2019                self.activate(mem, interrupt, queues)?;
2020                Ok(())
2021            }
2022        }
2023    }
2024
2025    fn virtio_snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
2026        match self.worker_state {
2027            WorkerState::Error => {
2028                return Err(anyhow!(
2029                    "failed to snapshot virtio gpu worker which is in error state"
2030                ));
2031            }
2032            WorkerState::Active => {
2033                return Err(anyhow!(
2034                    "failed to snapshot virtio gpu worker which is in active state"
2035                ));
2036            }
2037            _ => (),
2038        };
2039
2040        if let (Some(worker_request_sender), Some(worker_response_receiver)) =
2041            (&self.worker_request_sender, &self.worker_response_receiver)
2042        {
2043            worker_request_sender
2044                .send(WorkerRequest::Snapshot)
2045                .map_err(|e| {
2046                    anyhow!(
2047                        "failed to send snapshot request to virtio gpu worker: {:?}",
2048                        e
2049                    )
2050                })?;
2051
2052            match worker_response_receiver
2053                .recv()
2054                .inspect_err(|_| self.worker_state = WorkerState::Error)
2055                .context("failed to receive response for virtio gpu worker suspend request")??
2056            {
2057                WorkerResponse::Snapshot(snapshot) => Ok(AnySnapshot::to_any(snapshot)?),
2058                _ => {
2059                    panic!("unexpected response from virtio gpu worker sleep request");
2060                }
2061            }
2062        } else {
2063            Err(anyhow!("virtio gpu worker not available for snapshot"))
2064        }
2065    }
2066
2067    fn virtio_restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
2068        match self.worker_state {
2069            WorkerState::Error => {
2070                return Err(anyhow!(
2071                    "failed to restore virtio gpu worker which is in error state"
2072                ));
2073            }
2074            WorkerState::Active => {
2075                return Err(anyhow!(
2076                    "failed to restore virtio gpu worker which is in active state"
2077                ));
2078            }
2079            _ => (),
2080        };
2081
2082        let snapshot: WorkerSnapshot = AnySnapshot::from_any(data)?;
2083
2084        if let (Some(worker_request_sender), Some(worker_response_receiver)) =
2085            (&self.worker_request_sender, &self.worker_response_receiver)
2086        {
2087            worker_request_sender
2088                .send(WorkerRequest::Restore(snapshot))
2089                .map_err(|e| {
2090                    anyhow!(
2091                        "failed to send suspend request to virtio gpu worker: {:?}",
2092                        e
2093                    )
2094                })?;
2095
2096            let response = worker_response_receiver
2097                .recv()
2098                .inspect_err(|_| self.worker_state = WorkerState::Error)
2099                .context("failed to receive response for virtio gpu worker suspend request")??;
2100
2101            match response {
2102                WorkerResponse::Ok => Ok(()),
2103                _ => {
2104                    panic!("unexpected response from virtio gpu worker sleep request");
2105                }
2106            }
2107        } else {
2108            Err(anyhow!("virtio gpu worker not available for restore"))
2109        }
2110    }
2111
2112    fn reset(&mut self) -> anyhow::Result<()> {
2113        self.stop_worker_thread();
2114        Ok(())
2115    }
2116}
2117
2118impl Drop for Gpu {
2119    fn drop(&mut self) {
2120        let _ = self.reset();
2121    }
2122}
2123
2124/// This struct takes the ownership of resource bridges and tracks which ones should be processed.
2125struct ResourceBridges {
2126    resource_bridges: Vec<Tube>,
2127    should_process: Vec<bool>,
2128}
2129
2130impl ResourceBridges {
2131    pub fn new(resource_bridges: Vec<Tube>) -> Self {
2132        #[cfg(windows)]
2133        assert!(
2134            resource_bridges.is_empty(),
2135            "resource bridges are not supported on Windows"
2136        );
2137
2138        let mut resource_bridges = Self {
2139            resource_bridges,
2140            should_process: Default::default(),
2141        };
2142        resource_bridges.reset_should_process();
2143        resource_bridges
2144    }
2145
2146    // Appends raw descriptors of all resource bridges to the given vector.
2147    pub fn append_raw_descriptors(&self, rds: &mut Vec<RawDescriptor>) {
2148        for bridge in &self.resource_bridges {
2149            rds.push(bridge.as_raw_descriptor());
2150        }
2151    }
2152
2153    /// Adds all resource bridges to WaitContext.
2154    pub fn add_to_wait_context(&self, wait_ctx: &mut WaitContext<WorkerToken>) {
2155        for (index, bridge) in self.resource_bridges.iter().enumerate() {
2156            if let Err(e) = wait_ctx.add(bridge, WorkerToken::ResourceBridge { index }) {
2157                error!("failed to add resource bridge to WaitContext: {}", e);
2158            }
2159        }
2160    }
2161
2162    /// Marks that the resource bridge at the given index should be processed when
2163    /// `process_resource_bridges()` is called.
2164    pub fn set_should_process(&mut self, index: usize) {
2165        self.should_process[index] = true;
2166    }
2167
2168    /// Processes all resource bridges that have been marked as should be processed.  The markings
2169    /// will be cleared before returning. Faulty resource bridges will be removed from WaitContext.
2170    pub fn process_resource_bridges(
2171        &mut self,
2172        state: &mut Frontend,
2173        wait_ctx: &mut WaitContext<WorkerToken>,
2174    ) {
2175        for (bridge, &should_process) in self.resource_bridges.iter().zip(&self.should_process) {
2176            if should_process {
2177                if let Err(e) = state.process_resource_bridge(bridge) {
2178                    error!("Failed to process resource bridge: {:#}", e);
2179                    error!("Removing that resource bridge from the wait context.");
2180                    wait_ctx.delete(bridge).unwrap_or_else(|e| {
2181                        error!("Failed to remove faulty resource bridge: {:#}", e)
2182                    });
2183                }
2184            }
2185        }
2186        self.reset_should_process();
2187    }
2188
2189    fn reset_should_process(&mut self) {
2190        self.should_process.clear();
2191        self.should_process
2192            .resize(self.resource_bridges.len(), false);
2193    }
2194}