summary refs log tree commit diff
diff options
context:
space:
mode:
authorGurchetan Singh <gurchetansingh@chromium.org>2020-01-22 17:59:22 -0800
committerCommit Bot <commit-bot@chromium.org>2020-03-23 20:37:12 +0000
commit83fc5c49ba930a62ef1f4d93bc2004d779b6d16f (patch)
tree514d89cc061e6b34acaf5cbe10c254368729976a
parent151af70ac9778f5247f6fd58fe8b20c089604429 (diff)
downloadcrosvm-83fc5c49ba930a62ef1f4d93bc2004d779b6d16f.tar
crosvm-83fc5c49ba930a62ef1f4d93bc2004d779b6d16f.tar.gz
crosvm-83fc5c49ba930a62ef1f4d93bc2004d779b6d16f.tar.bz2
crosvm-83fc5c49ba930a62ef1f4d93bc2004d779b6d16f.tar.lz
crosvm-83fc5c49ba930a62ef1f4d93bc2004d779b6d16f.tar.xz
crosvm-83fc5c49ba930a62ef1f4d93bc2004d779b6d16f.tar.zst
crosvm-83fc5c49ba930a62ef1f4d93bc2004d779b6d16f.zip
devices: gpu: complete resource V2 rebase
* Remove RESOURCE_V2_UNREF
* Add RESOURCE_MAP/RESOURCE_UNMAP to enable resources without guest
  storage that don't need to be mapped directly either

BUG=chromium:924405
TEST=compile and test

Change-Id: I10d6cd120d86131fa7ed8917ddad25cdb99ae50c
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2015587
Tested-by: Gurchetan Singh <gurchetansingh@chromium.org>
Auto-Submit: Gurchetan Singh <gurchetansingh@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Commit-Queue: Gurchetan Singh <gurchetansingh@chromium.org>
-rw-r--r--devices/src/virtio/gpu/mod.rs18
-rw-r--r--devices/src/virtio/gpu/protocol.rs34
-rw-r--r--devices/src/virtio/gpu/virtio_3d_backend.rs216
-rw-r--r--vm_control/src/lib.rs9
4 files changed, 164 insertions, 113 deletions
diff --git a/devices/src/virtio/gpu/mod.rs b/devices/src/virtio/gpu/mod.rs
index d211768..93d004f 100644
--- a/devices/src/virtio/gpu/mod.rs
+++ b/devices/src/virtio/gpu/mod.rs
@@ -284,14 +284,17 @@ trait Backend {
         _flags: u32,
         _size: u64,
         _memory_id: u64,
-        _pci_addr: u64,
         _vecs: Vec<(GuestAddress, usize)>,
         _mem: &GuestMemory,
     ) -> GpuResponse {
         GpuResponse::ErrUnspec
     }
 
-    fn resource_v2_unref(&mut self, _resource_id: u32) -> GpuResponse {
+    fn resource_map(&mut self, _resource_id: u32, _pci_addr: u64) -> GpuResponse {
+        GpuResponse::ErrUnspec
+    }
+
+    fn resource_unmap(&mut self, _resource_id: u32) -> GpuResponse {
         GpuResponse::ErrUnspec
     }
 }
@@ -606,7 +609,6 @@ impl Frontend {
                 let ctx_id = info.hdr.ctx_id.to_native();
                 let flags = info.flags.to_native();
                 let size = info.size.to_native();
-                let pci_addr = info.pci_addr.to_native();
                 let memory_id = info.memory_id.to_native();
                 let entry_count = info.nr_entries.to_native();
                 if entry_count > VIRTIO_GPU_MAX_IOVEC_ENTRIES
@@ -632,15 +634,19 @@ impl Frontend {
                     ctx_id,
                     flags,
                     size,
-                    pci_addr,
                     memory_id,
                     vecs,
                     mem,
                 )
             }
-            GpuCommand::ResourceV2Unref(info) => {
+            GpuCommand::ResourceMap(info) => {
+                let resource_id = info.resource_id.to_native();
+                let offset = info.offset.to_native();
+                self.backend.resource_map(resource_id, offset)
+            }
+            GpuCommand::ResourceUnmap(info) => {
                 let resource_id = info.resource_id.to_native();
-                self.backend.resource_v2_unref(resource_id)
+                self.backend.resource_unmap(resource_id)
             }
         }
     }
diff --git a/devices/src/virtio/gpu/protocol.rs b/devices/src/virtio/gpu/protocol.rs
index 0563c1b..c98e289 100644
--- a/devices/src/virtio/gpu/protocol.rs
+++ b/devices/src/virtio/gpu/protocol.rs
@@ -50,7 +50,8 @@ pub const VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D: u32 = 0x206;
 pub const VIRTIO_GPU_CMD_SUBMIT_3D: u32 = 0x207;
 /* The following hypercalls are not upstreamed. */
 pub const VIRTIO_GPU_CMD_RESOURCE_CREATE_V2: u32 = 0x208;
-pub const VIRTIO_GPU_CMD_RESOURCE_CREATE_V2_UNREF: u32 = 0x209;
+pub const VIRTIO_GPU_CMD_RESOURCE_MAP: u32 = 0x209;
+pub const VIRTIO_GPU_CMD_RESOURCE_UNMAP: u32 = 0x20a;
 
 /* cursor commands */
 pub const VIRTIO_GPU_CMD_UPDATE_CURSOR: u32 = 0x300;
@@ -113,7 +114,8 @@ pub fn virtio_gpu_cmd_str(cmd: u32) -> &'static str {
         VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D => "VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D",
         VIRTIO_GPU_CMD_SUBMIT_3D => "VIRTIO_GPU_CMD_SUBMIT_3D",
         VIRTIO_GPU_CMD_RESOURCE_CREATE_V2 => "VIRTIO_GPU_CMD_RESOURCE_CREATE_V2",
-        VIRTIO_GPU_CMD_RESOURCE_CREATE_V2_UNREF => "VIRTIO_GPU_CMD_RESOURCE_CREATE_V2_UNREF",
+        VIRTIO_GPU_CMD_RESOURCE_MAP => "VIRTIO_GPU_RESOURCE_MAP",
+        VIRTIO_GPU_CMD_RESOURCE_UNMAP => "VIRTIO_GPU_RESOURCE_UNMAP",
         VIRTIO_GPU_CMD_UPDATE_CURSOR => "VIRTIO_GPU_CMD_UPDATE_CURSOR",
         VIRTIO_GPU_CMD_MOVE_CURSOR => "VIRTIO_GPU_CMD_MOVE_CURSOR",
         VIRTIO_GPU_RESP_OK_NODATA => "VIRTIO_GPU_RESP_OK_NODATA",
@@ -502,7 +504,6 @@ pub struct virtio_gpu_resource_create_v2 {
     pub resource_id: Le32,
     pub flags: Le32,
     pub size: Le64,
-    pub pci_addr: Le64,
     pub memory_id: Le64,
     pub nr_entries: Le32,
     pub padding: Le32,
@@ -512,13 +513,24 @@ unsafe impl DataInit for virtio_gpu_resource_create_v2 {}
 
 #[derive(Copy, Clone, Debug, Default)]
 #[repr(C)]
-pub struct virtio_gpu_resource_v2_unref {
+pub struct virtio_gpu_resource_map {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub resource_id: Le32,
+    pub map_flags: Le32,
+    pub offset: Le64,
+}
+
+unsafe impl DataInit for virtio_gpu_resource_map {}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct virtio_gpu_resource_unmap {
     pub hdr: virtio_gpu_ctrl_hdr,
     pub resource_id: Le32,
     pub padding: Le32,
 }
 
-unsafe impl DataInit for virtio_gpu_resource_v2_unref {}
+unsafe impl DataInit for virtio_gpu_resource_unmap {}
 
 /* simple formats for fbcon/X use */
 pub const VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: u32 = 1;
@@ -552,7 +564,8 @@ pub enum GpuCommand {
     TransferFromHost3d(virtio_gpu_transfer_host_3d),
     CmdSubmit3d(virtio_gpu_cmd_submit),
     ResourceCreateV2(virtio_gpu_resource_create_v2),
-    ResourceV2Unref(virtio_gpu_resource_v2_unref),
+    ResourceMap(virtio_gpu_resource_map),
+    ResourceUnmap(virtio_gpu_resource_unmap),
     UpdateCursor(virtio_gpu_update_cursor),
     MoveCursor(virtio_gpu_update_cursor),
 }
@@ -620,7 +633,8 @@ impl fmt::Debug for GpuCommand {
             TransferFromHost3d(_info) => f.debug_struct("TransferFromHost3d").finish(),
             CmdSubmit3d(_info) => f.debug_struct("CmdSubmit3d").finish(),
             ResourceCreateV2(_info) => f.debug_struct("ResourceCreateV2").finish(),
-            ResourceV2Unref(_info) => f.debug_struct("ResourceV2Unref").finish(),
+            ResourceMap(_info) => f.debug_struct("ResourceMap").finish(),
+            ResourceUnmap(_info) => f.debug_struct("ResourceUnmap").finish(),
             UpdateCursor(_info) => f.debug_struct("UpdateCursor").finish(),
             MoveCursor(_info) => f.debug_struct("MoveCursor").finish(),
         }
@@ -652,7 +666,8 @@ impl GpuCommand {
             VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D => TransferFromHost3d(cmd.read_obj()?),
             VIRTIO_GPU_CMD_SUBMIT_3D => CmdSubmit3d(cmd.read_obj()?),
             VIRTIO_GPU_CMD_RESOURCE_CREATE_V2 => ResourceCreateV2(cmd.read_obj()?),
-            VIRTIO_GPU_CMD_RESOURCE_CREATE_V2_UNREF => ResourceV2Unref(cmd.read_obj()?),
+            VIRTIO_GPU_CMD_RESOURCE_MAP => ResourceMap(cmd.read_obj()?),
+            VIRTIO_GPU_CMD_RESOURCE_UNMAP => ResourceUnmap(cmd.read_obj()?),
             VIRTIO_GPU_CMD_UPDATE_CURSOR => UpdateCursor(cmd.read_obj()?),
             VIRTIO_GPU_CMD_MOVE_CURSOR => MoveCursor(cmd.read_obj()?),
             _ => return Err(GpuCommandDecodeError::InvalidType(hdr.type_.into())),
@@ -682,7 +697,8 @@ impl GpuCommand {
             TransferFromHost3d(info) => &info.hdr,
             CmdSubmit3d(info) => &info.hdr,
             ResourceCreateV2(info) => &info.hdr,
-            ResourceV2Unref(info) => &info.hdr,
+            ResourceMap(info) => &info.hdr,
+            ResourceUnmap(info) => &info.hdr,
             UpdateCursor(info) => &info.hdr,
             MoveCursor(info) => &info.hdr,
         }
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
+            }
         }
     }
 }
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs
index 298d800..b2577d9 100644
--- a/vm_control/src/lib.rs
+++ b/vm_control/src/lib.rs
@@ -192,7 +192,7 @@ pub enum VmMemoryRequest {
     RegisterMemory(MaybeOwnedFd, usize),
     /// Similiar to `VmMemoryRequest::RegisterMemory`, but doesn't allocate new address space.
     /// Useful for cases where the address space is already allocated (PCI regions).
-    RegisterMemoryAtAddress(Alloc, MaybeOwnedFd, usize, u64),
+    RegisterFdAtPciBarOffset(Alloc, MaybeOwnedFd, usize, u64),
     /// Unregister the given memory slot that was previously registereed with `RegisterMemory`.
     UnregisterMemory(u32),
     /// Allocate GPU buffer of a given size/format and register the memory into guest address space.
@@ -230,8 +230,8 @@ impl VmMemoryRequest {
                     Err(e) => VmMemoryResponse::Err(e),
                 }
             }
-            RegisterMemoryAtAddress(alloc, ref fd, size, guest_addr) => {
-                match register_memory(vm, sys_allocator, fd, size, Some((alloc, guest_addr))) {
+            RegisterFdAtPciBarOffset(alloc, ref fd, size, offset) => {
+                match register_memory(vm, sys_allocator, fd, size, Some((alloc, offset))) {
                     Ok((pfn, slot)) => VmMemoryResponse::RegisterMemory { pfn, slot },
                     Err(e) => VmMemoryResponse::Err(e),
                 }
@@ -433,12 +433,13 @@ fn register_memory(
     };
 
     let addr = match allocation {
-        Some((Alloc::PciBar { bus, dev, bar }, address)) => {
+        Some((Alloc::PciBar { bus, dev, bar }, offset)) => {
             match allocator
                 .mmio_allocator(MmioType::High)
                 .get(&Alloc::PciBar { bus, dev, bar })
             {
                 Some((start_addr, length, _)) => {
+                    let address = *start_addr + offset;
                     let range = *start_addr..*start_addr + *length;
                     let end = address + (size as u64);
                     match (range.contains(&address), range.contains(&end)) {