summary refs log tree commit diff
path: root/devices/src/virtio/gpu/virtio_3d_backend.rs
diff options
context:
space:
mode:
Diffstat (limited to 'devices/src/virtio/gpu/virtio_3d_backend.rs')
-rw-r--r--devices/src/virtio/gpu/virtio_3d_backend.rs216
1 files changed, 122 insertions, 94 deletions
diff --git a/devices/src/virtio/gpu/virtio_3d_backend.rs b/devices/src/virtio/gpu/virtio_3d_backend.rs
index 21b5bf4..3ede8a6 100644
--- a/devices/src/virtio/gpu/virtio_3d_backend.rs
+++ b/devices/src/virtio/gpu/virtio_3d_backend.rs
@@ -44,6 +44,8 @@ struct Virtio3DResource {
     gpu_resource: GpuRendererResource,
     display_import: Option<(Rc<RefCell<GpuDisplay>>, u32)>,
     kvm_slot: Option<u32>,
+    size: u64,
+    flags: u32,
 }
 
 impl Virtio3DResource {
@@ -54,27 +56,38 @@ impl Virtio3DResource {
             gpu_resource,
             display_import: None,
             kvm_slot: None,
+            flags: 0,
+            // The size of the host resource isn't really zero, but it's undefined by
+            // virtio_gpu_resource_create_3d
+            size: 0,
         }
     }
 
     pub fn v2_new(
         width: u32,
         height: u32,
-        kvm_slot: u32,
         gpu_resource: GpuRendererResource,
+        flags: u32,
+        size: u64,
     ) -> Virtio3DResource {
         Virtio3DResource {
             width,
             height,
             gpu_resource,
             display_import: None,
-            kvm_slot: Some(kvm_slot),
+            kvm_slot: None,
+            flags,
+            size,
         }
     }
 
     fn as_mut(&mut self) -> &mut dyn VirtioResource {
         self
     }
+
+    fn use_flags(&self) -> u32 {
+        self.flags & VIRTIO_GPU_RESOURCE_USE_MASK
+    }
 }
 
 impl VirtioResource for Virtio3DResource {
@@ -765,7 +778,6 @@ impl Backend for Virtio3DBackend {
         ctx_id: u32,
         flags: u32,
         size: u64,
-        pci_addr: u64,
         memory_id: u64,
         vecs: Vec<(GuestAddress, usize)>,
         mem: &GuestMemory,
@@ -788,103 +800,119 @@ impl Backend for Virtio3DBackend {
                     }
                 };
 
-                let use_flags = VIRTIO_GPU_RESOURCE_USE_MASK & flags;
-                match use_flags {
-                    VIRTIO_GPU_RESOURCE_USE_MAPPABLE => {
-                        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(Virtio3DResource::v2_new(
-                                            self.base.display_width,
-                                            self.base.display_height,
-                                            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(Virtio3DResource::new(
-                            self.base.display_width,
-                            self.base.display_height,
-                            resource,
-                        ));
+                entry.insert(Virtio3DResource::v2_new(
+                    self.base.display_width,
+                    self.base.display_height,
+                    resource,
+                    flags,
+                    size,
+                ));
 
-                        GpuResponse::OkNoData
-                    }
-                }
+                GpuResponse::OkNoData
             }
             Entry::Occupied(_) => GpuResponse::ErrInvalidResourceId,
         }
     }
 
-    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,
+    fn resource_map(&mut self, resource_id: u32, offset: u64) -> GpuResponse {
+        let resource = match self.resources.get_mut(&resource_id) {
+            Some(r) => r,
+            None => return GpuResponse::ErrInvalidResourceId,
+        };
+
+        if resource.use_flags() & VIRTIO_GPU_RESOURCE_USE_MAPPABLE == 0 {
+            error!("resource not mappable");
+            return GpuResponse::ErrUnspec;
+        }
+
+        let dma_buf_fd = match resource.gpu_resource.export() {
+            Ok(export) => export.1,
+            Err(e) => {
+                error!("failed to export plane fd: {}", e);
+                return GpuResponse::ErrUnspec;
+            }
+        };
+
+        let request = VmMemoryRequest::RegisterFdAtPciBarOffset(
+            self.pci_bar,
+            MaybeOwnedFd::Borrowed(dma_buf_fd.as_raw_fd()),
+            resource.size as usize,
+            offset,
+        );
+
+        match self.gpu_device_socket.send(&request) {
+            Ok(_) => (),
+            Err(e) => {
+                error!("failed to send request: {}", e);
+                return GpuResponse::ErrUnspec;
+            }
+        }
+
+        let response = match self.gpu_device_socket.recv() {
+            Ok(response) => response,
+            Err(e) => {
+                error!("failed to receive data: {}", e);
+                return GpuResponse::ErrUnspec;
+            }
+        };
+
+        match response {
+            VmMemoryResponse::RegisterMemory { pfn: _, slot } => {
+                resource.kvm_slot = Some(slot);
+                GpuResponse::OkNoData
+            }
+            VmMemoryResponse::Err(e) => {
+                error!("received an error: {}", e);
+                GpuResponse::ErrUnspec
+            }
+            _ => {
+                error!("recieved an unexpected response");
+                GpuResponse::ErrUnspec
+            }
+        }
+    }
+
+    fn resource_unmap(&mut self, resource_id: u32) -> GpuResponse {
+        let resource = match self.resources.get_mut(&resource_id) {
+            Some(r) => r,
+            None => return GpuResponse::ErrInvalidResourceId,
+        };
+
+        let kvm_slot = match resource.kvm_slot {
+            Some(kvm_slot) => kvm_slot,
+            None => return GpuResponse::ErrUnspec,
+        };
+
+        let request = VmMemoryRequest::UnregisterMemory(kvm_slot);
+        match self.gpu_device_socket.send(&request) {
+            Ok(_) => (),
+            Err(e) => {
+                error!("failed to send request: {}", e);
+                return GpuResponse::ErrUnspec;
+            }
+        }
+
+        let response = match self.gpu_device_socket.recv() {
+            Ok(response) => response,
+            Err(e) => {
+                error!("failed to receive data: {}", e);
+                return GpuResponse::ErrUnspec;
+            }
+        };
+
+        match response {
+            VmMemoryResponse::Ok => {
+                resource.kvm_slot = None;
+                GpuResponse::OkNoData
+            }
+            VmMemoryResponse::Err(e) => {
+                error!("received an error: {}", e);
+                GpuResponse::ErrUnspec
+            }
+            _ => {
+                error!("recieved an unexpected response");
+                GpuResponse::ErrUnspec
+            }
         }
     }
 }