summary refs log tree commit diff
path: root/devices/src/virtio/gpu/backend.rs
diff options
context:
space:
mode:
Diffstat (limited to 'devices/src/virtio/gpu/backend.rs')
-rw-r--r--devices/src/virtio/gpu/backend.rs144
1 files changed, 140 insertions, 4 deletions
diff --git a/devices/src/virtio/gpu/backend.rs b/devices/src/virtio/gpu/backend.rs
index 4cfac7a..75dbdaf 100644
--- a/devices/src/virtio/gpu/backend.rs
+++ b/devices/src/virtio/gpu/backend.rs
@@ -24,10 +24,11 @@ use gpu_renderer::{
 
 use super::protocol::{
     AllocationMetadataResponse, GpuResponse, GpuResponsePlaneInfo, VIRTIO_GPU_CAPSET3,
-    VIRTIO_GPU_CAPSET_VIRGL, VIRTIO_GPU_CAPSET_VIRGL2,
+    VIRTIO_GPU_CAPSET_VIRGL, VIRTIO_GPU_CAPSET_VIRGL2, VIRTIO_GPU_MEMORY_HOST_COHERENT,
 };
 use crate::virtio::resource_bridge::*;
-use vm_control::VmMemoryControlRequestSocket;
+
+use vm_control::{MaybeOwnedFd, VmMemoryControlRequestSocket, VmMemoryRequest, VmMemoryResponse};
 
 const DEFAULT_WIDTH: u32 = 1280;
 const DEFAULT_HEIGHT: u32 = 1024;
@@ -37,6 +38,7 @@ struct VirtioGpuResource {
     height: u32,
     gpu_resource: GpuRendererResource,
     display_import: Option<(Rc<RefCell<GpuDisplay>>, u32)>,
+    kvm_slot: Option<u32>,
 }
 
 impl VirtioGpuResource {
@@ -46,6 +48,19 @@ impl VirtioGpuResource {
             height,
             gpu_resource,
             display_import: None,
+            kvm_slot: None,
+        }
+    }
+
+    pub fn v2_new(kvm_slot: u32, gpu_resource: GpuRendererResource) -> VirtioGpuResource {
+        // Choose DEFAULT_WIDTH and DEFAULT_HEIGHT, since that matches the default modes
+        // for virtgpu-kms.
+        VirtioGpuResource {
+            width: DEFAULT_WIDTH,
+            height: DEFAULT_HEIGHT,
+            gpu_resource,
+            display_import: None,
+            kvm_slot: Some(kvm_slot),
         }
     }
 
@@ -143,13 +158,11 @@ pub struct Backend {
     renderer: Renderer,
     resources: Map<u32, VirtioGpuResource>,
     contexts: Map<u32, RendererContext>,
-    #[allow(dead_code)]
     gpu_device_socket: VmMemoryControlRequestSocket,
     scanout_surface: Option<u32>,
     cursor_surface: Option<u32>,
     scanout_resource: u32,
     cursor_resource: u32,
-    #[allow(dead_code)]
     pci_bar: Alloc,
 }
 
@@ -802,4 +815,127 @@ impl Backend {
             }
         }
     }
+
+    pub fn resource_create_v2(
+        &mut self,
+        resource_id: u32,
+        guest_memory_type: u32,
+        guest_caching_type: u32,
+        size: u64,
+        pci_addr: u64,
+        mem: &GuestMemory,
+        vecs: Vec<(GuestAddress, usize)>,
+        args: Vec<u8>,
+    ) -> GpuResponse {
+        match self.resources.entry(resource_id) {
+            Entry::Vacant(entry) => {
+                let resource = match self.renderer.resource_create_v2(
+                    resource_id,
+                    guest_memory_type,
+                    guest_caching_type,
+                    size,
+                    mem,
+                    &vecs,
+                    &args,
+                ) {
+                    Ok(resource) => resource,
+                    Err(e) => {
+                        error!("failed to create resource: {}", e);
+                        return GpuResponse::ErrUnspec;
+                    }
+                };
+
+                match guest_memory_type {
+                    VIRTIO_GPU_MEMORY_HOST_COHERENT => {
+                        let dma_buf_fd = match resource.export() {
+                            Ok(export) => export.1,
+                            Err(e) => {
+                                error!("failed to export plane fd: {}", e);
+                                return GpuResponse::ErrUnspec;
+                            }
+                        };
+
+                        let request = VmMemoryRequest::RegisterMemoryAtAddress(
+                            self.pci_bar,
+                            MaybeOwnedFd::Borrowed(dma_buf_fd.as_raw_fd()),
+                            size as usize,
+                            pci_addr,
+                        );
+
+                        match self.gpu_device_socket.send(&request) {
+                            Ok(_resq) => match self.gpu_device_socket.recv() {
+                                Ok(response) => match response {
+                                    VmMemoryResponse::RegisterMemory { pfn: _, slot } => {
+                                        entry.insert(VirtioGpuResource::v2_new(slot, resource));
+                                        GpuResponse::OkNoData
+                                    }
+                                    VmMemoryResponse::Err(e) => {
+                                        error!("received an error: {}", e);
+                                        GpuResponse::ErrUnspec
+                                    }
+                                    _ => {
+                                        error!("recieved an unexpected response");
+                                        GpuResponse::ErrUnspec
+                                    }
+                                },
+                                Err(e) => {
+                                    error!("failed to receive data: {}", e);
+                                    GpuResponse::ErrUnspec
+                                }
+                            },
+                            Err(e) => {
+                                error!("failed to send request: {}", e);
+                                GpuResponse::ErrUnspec
+                            }
+                        }
+                    }
+                    _ => {
+                        entry.insert(VirtioGpuResource::new(
+                            DEFAULT_WIDTH,
+                            DEFAULT_HEIGHT,
+                            resource,
+                        ));
+
+                        GpuResponse::OkNoData
+                    }
+                }
+            }
+            Entry::Occupied(_) => GpuResponse::ErrInvalidResourceId,
+        }
+    }
+
+    pub fn resource_v2_unref(&mut self, resource_id: u32) -> GpuResponse {
+        match self.resources.remove(&resource_id) {
+            Some(entry) => match entry.kvm_slot {
+                Some(kvm_slot) => {
+                    let request = VmMemoryRequest::UnregisterMemory(kvm_slot);
+                    match self.gpu_device_socket.send(&request) {
+                        Ok(_resq) => match self.gpu_device_socket.recv() {
+                            Ok(response) => match response {
+                                VmMemoryResponse::Ok => GpuResponse::OkNoData,
+                                VmMemoryResponse::Err(e) => {
+                                    error!("received an error: {}", e);
+                                    GpuResponse::ErrUnspec
+                                }
+                                _ => {
+                                    error!("recieved an unexpected response");
+                                    GpuResponse::ErrUnspec
+                                }
+                            },
+                            Err(e) => {
+                                error!("failed to receive data: {}", e);
+                                GpuResponse::ErrUnspec
+                            }
+                        },
+                        Err(e) => {
+                            error!("failed to send request: {}", e);
+                            GpuResponse::ErrUnspec
+                        }
+                    }
+                }
+                None => GpuResponse::OkNoData,
+            },
+            None => GpuResponse::ErrInvalidResourceId,
+        }
+    }
 }