mirror of
https://github.com/rust-vmm/vhost-device.git
synced 2025-12-26 22:48:17 +00:00
Merge a623fefea6 into 8d7873a699
This commit is contained in:
commit
36d8a17ed6
83
Cargo.lock
generated
83
Cargo.lock
generated
@ -2006,6 +2006,18 @@ dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vhost"
|
||||
version = "0.15.0"
|
||||
source = "git+https://github.com/mtjhrc/vhost.git?branch=shmem#c686ebb25a0af340a7969f637ba0d1b1e160fe6c"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"libc 0.2.177",
|
||||
"uuid",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vhost-device-can"
|
||||
version = "0.1.0"
|
||||
@ -2017,8 +2029,8 @@ dependencies = [
|
||||
"queues",
|
||||
"socketcan",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vhost-user-backend 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
@ -2038,8 +2050,8 @@ dependencies = [
|
||||
"log",
|
||||
"queues",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vhost-user-backend 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
@ -2057,8 +2069,8 @@ dependencies = [
|
||||
"libgpiod",
|
||||
"log",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vhost-user-backend 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
@ -2080,8 +2092,8 @@ dependencies = [
|
||||
"rutabaga_gfx",
|
||||
"tempfile",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (git+https://github.com/mtjhrc/vhost.git?branch=shmem)",
|
||||
"vhost-user-backend 0.21.0 (git+https://github.com/mtjhrc/vhost.git?branch=shmem)",
|
||||
"virglrenderer",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
@ -2099,8 +2111,8 @@ dependencies = [
|
||||
"libc 0.2.177",
|
||||
"log",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vhost-user-backend 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
@ -2122,8 +2134,8 @@ dependencies = [
|
||||
"rand",
|
||||
"tempfile",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vhost-user-backend 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
@ -2143,8 +2155,8 @@ dependencies = [
|
||||
"rand",
|
||||
"tempfile",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vhost-user-backend 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
@ -2161,8 +2173,8 @@ dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"log",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vhost-user-backend 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
@ -2180,8 +2192,8 @@ dependencies = [
|
||||
"log",
|
||||
"tempfile",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vhost-user-backend 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
@ -2205,8 +2217,8 @@ dependencies = [
|
||||
"rusty-fork",
|
||||
"tempfile",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vhost-user-backend 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
@ -2224,8 +2236,8 @@ dependencies = [
|
||||
"libc 0.2.177",
|
||||
"log",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vhost-user-backend 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
@ -2242,8 +2254,8 @@ dependencies = [
|
||||
"libc 0.2.177",
|
||||
"log",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vhost-user-backend 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
@ -2265,8 +2277,8 @@ dependencies = [
|
||||
"serde",
|
||||
"tempfile",
|
||||
"thiserror 2.0.17",
|
||||
"vhost",
|
||||
"vhost-user-backend",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vhost-user-backend 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"virtio-vsock",
|
||||
@ -2283,7 +2295,21 @@ checksum = "783587813a59c42c36519a6e12bb31eb2d7fa517377428252ba4cc2312584243"
|
||||
dependencies = [
|
||||
"libc 0.2.177",
|
||||
"log",
|
||||
"vhost",
|
||||
"vhost 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vhost-user-backend"
|
||||
version = "0.21.0"
|
||||
source = "git+https://github.com/mtjhrc/vhost.git?branch=shmem#c686ebb25a0af340a7969f637ba0d1b1e160fe6c"
|
||||
dependencies = [
|
||||
"libc 0.2.177",
|
||||
"log",
|
||||
"vhost 0.15.0 (git+https://github.com/mtjhrc/vhost.git?branch=shmem)",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
@ -2293,8 +2319,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "virglrenderer"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14b3ceb5f84adcbd531661a6c6c0883c3d6cd83427886d3179675b19268f4450"
|
||||
source = "git+https://gitlab.freedesktop.org/mtjhrc/virglrenderer-rs.git?branch=map_info#a4b3fb2efe39f06c5ea1d96a0a51c3f66df0f79b"
|
||||
dependencies = [
|
||||
"libc 1.0.0-alpha.1",
|
||||
"log",
|
||||
|
||||
@ -28,9 +28,9 @@ log = "0.4"
|
||||
[target.'cfg(not(target_env = "musl"))'.dependencies]
|
||||
rutabaga_gfx = "0.1.75"
|
||||
thiserror = "2.0.17"
|
||||
virglrenderer = {version = "0.1.2", optional = true }
|
||||
vhost = { version = "0.15.0", features = ["vhost-user-backend"] }
|
||||
vhost-user-backend = "0.21"
|
||||
virglrenderer = { git = "https://gitlab.freedesktop.org/mtjhrc/virglrenderer-rs.git", branch = "map_info", optional = true }
|
||||
vhost = { git = "https://github.com/mtjhrc/vhost.git", branch = "shmem", features = ["vhost-user-backend"] }
|
||||
vhost-user-backend = { git = "https://github.com/mtjhrc/vhost.git", branch = "shmem" }
|
||||
virtio-bindings = "0.2.5"
|
||||
virtio-queue = "0.17.0"
|
||||
vm-memory = "0.17.1"
|
||||
|
||||
@ -2,12 +2,16 @@
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{
|
||||
os::fd::{AsFd, AsRawFd},
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use log::{debug, error};
|
||||
use log::{debug, error, trace};
|
||||
use vhost::vhost_user::{
|
||||
gpu_message::{VhostUserGpuCursorPos, VhostUserGpuCursorUpdate, VhostUserGpuEdidRequest},
|
||||
GpuBackend,
|
||||
message::{VhostUserMMap, VhostUserMMapFlags},
|
||||
Backend, GpuBackend, VhostUserFrontendReqHandler,
|
||||
};
|
||||
use vm_memory::VolatileSlice;
|
||||
|
||||
@ -21,6 +25,59 @@ use crate::{
|
||||
renderer::Renderer,
|
||||
};
|
||||
|
||||
/// Common helper for mapping blob resources.
|
||||
/// Maps a blob resource using the vhost-user backend's shmem_map.
|
||||
pub fn common_map_blob(
|
||||
backend: &Backend,
|
||||
flags: VhostUserMMapFlags,
|
||||
handle_fd: &(impl AsFd + AsRawFd),
|
||||
blob_size: u64,
|
||||
offset: u64,
|
||||
resource_id: u32,
|
||||
) -> Result<(), GpuResponse> {
|
||||
trace!("Mapping blob resource_id={resource_id} offset={offset} size={blob_size}");
|
||||
|
||||
let map_request = VhostUserMMap {
|
||||
shmid: 0,
|
||||
padding: Default::default(),
|
||||
fd_offset: 0,
|
||||
shm_offset: offset,
|
||||
len: blob_size,
|
||||
flags: flags.bits(),
|
||||
};
|
||||
|
||||
backend.shmem_map(&map_request, handle_fd).map_err(|e| {
|
||||
error!("Failed to mmap by frontend: {e:?}");
|
||||
ErrUnspec
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Common helper for unmapping blob resources.
|
||||
/// Unmaps a blob resource using the vhost-user backend's shmem_unmap.
|
||||
pub fn common_unmap_blob(
|
||||
backend: &Backend,
|
||||
blob_size: u64,
|
||||
offset: u64,
|
||||
) -> Result<(), GpuResponse> {
|
||||
let unmap_request = VhostUserMMap {
|
||||
shmid: 0,
|
||||
padding: Default::default(),
|
||||
fd_offset: 0,
|
||||
shm_offset: offset,
|
||||
len: blob_size,
|
||||
flags: 0,
|
||||
};
|
||||
|
||||
backend.shmem_unmap(&unmap_request).map_err(|e| {
|
||||
error!("Failed to unmap by frontend: {e:?}");
|
||||
ErrUnspec
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VirtioGpuScanout {
|
||||
pub resource_id: u32,
|
||||
|
||||
@ -8,7 +8,10 @@ use std::{
|
||||
cell::RefCell,
|
||||
collections::BTreeMap,
|
||||
io::IoSliceMut,
|
||||
os::{fd::FromRawFd, raw::c_void},
|
||||
os::{
|
||||
fd::{AsFd, FromRawFd},
|
||||
raw::c_void,
|
||||
},
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
@ -16,32 +19,39 @@ use log::{debug, error, warn};
|
||||
use rutabaga_gfx::{
|
||||
ResourceCreate3D, Rutabaga, RutabagaBuilder, RutabagaComponentType, RutabagaFence,
|
||||
RutabagaFenceHandler, RutabagaHandle, RutabagaIntoRawDescriptor, RutabagaIovec, Transfer3D,
|
||||
RUTABAGA_HANDLE_TYPE_MEM_OPAQUE_FD, RUTABAGA_MAP_ACCESS_MASK, RUTABAGA_MAP_ACCESS_READ,
|
||||
RUTABAGA_MAP_ACCESS_RW, RUTABAGA_MAP_ACCESS_WRITE, RUTABAGA_MAP_CACHE_MASK,
|
||||
};
|
||||
use vhost::vhost_user::{
|
||||
gpu_message::{
|
||||
VhostUserGpuCursorPos, VhostUserGpuEdidRequest, VhostUserGpuScanout, VhostUserGpuUpdate,
|
||||
},
|
||||
GpuBackend,
|
||||
message::VhostUserMMapFlags,
|
||||
Backend, GpuBackend,
|
||||
};
|
||||
use vhost_user_backend::{VringRwLock, VringT};
|
||||
use virtio_bindings::virtio_gpu::VIRTIO_GPU_BLOB_MEM_HOST3D;
|
||||
use vm_memory::{GuestAddress, GuestMemory, GuestMemoryMmap, VolatileSlice};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
use crate::{
|
||||
backend::{
|
||||
common,
|
||||
common::{common_set_scanout_disable, AssociatedScanouts, CursorConfig, VirtioGpuScanout},
|
||||
common::{
|
||||
common_map_blob, common_set_scanout_disable, common_unmap_blob, AssociatedScanouts,
|
||||
CursorConfig, VirtioGpuScanout,
|
||||
},
|
||||
},
|
||||
device::Error,
|
||||
gpu_types::{FenceState, ResourceCreate3d, Transfer3DDesc, VirtioGpuRing},
|
||||
gpu_types::{FenceState, ResourceCreate3d, ResourceCreateBlob, Transfer3DDesc, VirtioGpuRing},
|
||||
protocol::{
|
||||
virtio_gpu_rect, GpuResponse,
|
||||
GpuResponse::{
|
||||
ErrInvalidParameter, ErrInvalidResourceId, ErrUnspec, OkCapset, OkCapsetInfo, OkNoData,
|
||||
OkResourcePlaneInfo,
|
||||
ErrInvalidParameter, ErrInvalidResourceId, ErrUnspec, OkCapset, OkCapsetInfo,
|
||||
OkMapInfo, OkNoData, OkResourcePlaneInfo,
|
||||
},
|
||||
GpuResponsePlaneInfo, VirtioGpuResult, VIRTIO_GPU_FLAG_INFO_RING_IDX,
|
||||
VIRTIO_GPU_MAX_SCANOUTS,
|
||||
GpuResponsePlaneInfo, VirtioGpuResult, VIRTIO_GPU_BLOB_FLAG_CREATE_GUEST_HANDLE,
|
||||
VIRTIO_GPU_FLAG_INFO_RING_IDX, VIRTIO_GPU_MAX_SCANOUTS,
|
||||
},
|
||||
renderer::Renderer,
|
||||
GpuConfig,
|
||||
@ -59,6 +69,8 @@ pub struct GfxstreamResource {
|
||||
scanouts: common::AssociatedScanouts,
|
||||
pub info_3d: Option<rutabaga_gfx::Resource3DInfo>,
|
||||
pub handle: Option<Arc<RutabagaHandle>>,
|
||||
pub blob_size: u64,
|
||||
pub blob_shmem_offset: Option<u64>,
|
||||
}
|
||||
|
||||
impl GfxstreamResource {
|
||||
@ -85,6 +97,8 @@ impl GfxstreamResource {
|
||||
scanouts: AssociatedScanouts::default(),
|
||||
info_3d: None,
|
||||
handle: None,
|
||||
blob_size: 0,
|
||||
blob_shmem_offset: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,6 +110,8 @@ thread_local! {
|
||||
}
|
||||
|
||||
pub struct GfxstreamAdapter {
|
||||
#[allow(dead_code)]
|
||||
backend: Backend,
|
||||
gpu_backend: GpuBackend,
|
||||
resources: BTreeMap<u32, GfxstreamResource>,
|
||||
fence_state: Arc<Mutex<FenceState>>,
|
||||
@ -103,7 +119,12 @@ pub struct GfxstreamAdapter {
|
||||
}
|
||||
|
||||
impl GfxstreamAdapter {
|
||||
pub fn new(queue_ctl: &VringRwLock, gpu_config: &GpuConfig, gpu_backend: GpuBackend) -> Self {
|
||||
pub fn new(
|
||||
queue_ctl: &VringRwLock,
|
||||
backend: Backend,
|
||||
gpu_config: &GpuConfig,
|
||||
gpu_backend: GpuBackend,
|
||||
) -> Self {
|
||||
let fence_state = Arc::new(Mutex::new(FenceState::default()));
|
||||
let fence = Self::create_fence_handler(queue_ctl.clone(), fence_state.clone());
|
||||
|
||||
@ -117,6 +138,7 @@ impl GfxstreamAdapter {
|
||||
});
|
||||
|
||||
Self {
|
||||
backend,
|
||||
gpu_backend,
|
||||
fence_state,
|
||||
resources: BTreeMap::new(),
|
||||
@ -281,6 +303,8 @@ impl Renderer for GfxstreamAdapter {
|
||||
scanouts: AssociatedScanouts::default(),
|
||||
info_3d: None,
|
||||
handle: None,
|
||||
blob_size: 0,
|
||||
blob_shmem_offset: None,
|
||||
};
|
||||
debug_assert!(
|
||||
!self.resources.contains_key(&resource_id),
|
||||
@ -653,25 +677,119 @@ impl Renderer for GfxstreamAdapter {
|
||||
|
||||
fn resource_create_blob(
|
||||
&mut self,
|
||||
_ctx_id: u32,
|
||||
_resource_id: u32,
|
||||
_blob_id: u64,
|
||||
_size: u64,
|
||||
_blob_mem: u32,
|
||||
_blob_flags: u32,
|
||||
ctx_id: u32,
|
||||
resource_create_blob: ResourceCreateBlob,
|
||||
vecs: Vec<(vm_memory::GuestAddress, usize)>,
|
||||
mem: &vm_memory::GuestMemoryMmap,
|
||||
) -> VirtioGpuResult {
|
||||
error!("Not implemented: resource_create_blob");
|
||||
Err(ErrUnspec)
|
||||
let mut rutabaga_iovecs = None;
|
||||
|
||||
if resource_create_blob.blob_flags & VIRTIO_GPU_BLOB_FLAG_CREATE_GUEST_HANDLE != 0 {
|
||||
panic!("GUEST_HANDLE unimplemented");
|
||||
} else if resource_create_blob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D {
|
||||
rutabaga_iovecs =
|
||||
Some(Self::sglist_to_rutabaga_iovecs(&vecs[..], mem).map_err(|_| ErrUnspec)?);
|
||||
}
|
||||
|
||||
Self::with_rutabaga(|rutabaga| {
|
||||
rutabaga.resource_create_blob(
|
||||
ctx_id,
|
||||
resource_create_blob.resource_id,
|
||||
resource_create_blob.into(),
|
||||
rutabaga_iovecs,
|
||||
None,
|
||||
)
|
||||
})?;
|
||||
|
||||
let resource = GfxstreamResource {
|
||||
id: resource_create_blob.resource_id,
|
||||
width: 0,
|
||||
height: 0,
|
||||
scanouts: AssociatedScanouts::default(),
|
||||
info_3d: None,
|
||||
handle: None,
|
||||
blob_size: resource_create_blob.size,
|
||||
blob_shmem_offset: None,
|
||||
};
|
||||
|
||||
debug_assert!(
|
||||
!self
|
||||
.resources
|
||||
.contains_key(&resource_create_blob.resource_id),
|
||||
"Resource ID {} already exists in the resources map.",
|
||||
resource_create_blob.resource_id
|
||||
);
|
||||
|
||||
// Rely on rutabaga to check for duplicate resource ids.
|
||||
self.resources
|
||||
.insert(resource_create_blob.resource_id, resource);
|
||||
Ok(Self::result_from_query(resource_create_blob.resource_id))
|
||||
}
|
||||
|
||||
fn resource_map_blob(&mut self, _resource_id: u32, _offset: u64) -> VirtioGpuResult {
|
||||
error!("Not implemented: resource_map_blob");
|
||||
Err(ErrUnspec)
|
||||
fn resource_map_blob(&mut self, resource_id: u32, offset: u64) -> VirtioGpuResult {
|
||||
let resource = self
|
||||
.resources
|
||||
.get_mut(&resource_id)
|
||||
.ok_or(ErrInvalidResourceId)?;
|
||||
|
||||
let map_info = Self::with_rutabaga(|rutabaga| rutabaga.map_info(resource_id))
|
||||
.map_err(|_| ErrUnspec)?;
|
||||
|
||||
let export = Self::with_rutabaga(|rutabaga| rutabaga.export_blob(resource_id))
|
||||
.map_err(|_| ErrUnspec)?;
|
||||
|
||||
// Check handle type - we don't support OPAQUE_FD mapping
|
||||
if export.handle_type == RUTABAGA_HANDLE_TYPE_MEM_OPAQUE_FD {
|
||||
return Err(ErrUnspec);
|
||||
}
|
||||
|
||||
// Convert map_info access flags to VhostUserMMapFlags
|
||||
let flags = match map_info & RUTABAGA_MAP_ACCESS_MASK {
|
||||
RUTABAGA_MAP_ACCESS_READ => VhostUserMMapFlags::default(),
|
||||
RUTABAGA_MAP_ACCESS_WRITE => VhostUserMMapFlags::WRITABLE,
|
||||
RUTABAGA_MAP_ACCESS_RW => VhostUserMMapFlags::WRITABLE,
|
||||
_ => {
|
||||
error!("Invalid access mask for blob resource, map_info: {map_info}");
|
||||
return Err(ErrUnspec);
|
||||
}
|
||||
};
|
||||
|
||||
common_map_blob(
|
||||
&self.backend,
|
||||
flags,
|
||||
&export.os_handle.as_fd(),
|
||||
resource.blob_size,
|
||||
offset,
|
||||
resource_id,
|
||||
)?;
|
||||
|
||||
resource.blob_shmem_offset = Some(offset);
|
||||
|
||||
// Return cache flags only (access flags not part of virtio-gpu spec)
|
||||
Ok(OkMapInfo {
|
||||
map_info: map_info & RUTABAGA_MAP_CACHE_MASK,
|
||||
})
|
||||
}
|
||||
|
||||
fn resource_unmap_blob(&mut self, _resource_id: u32) -> VirtioGpuResult {
|
||||
error!("Not implemented: resource_unmap_blob");
|
||||
Err(ErrUnspec)
|
||||
fn resource_unmap_blob(&mut self, resource_id: u32) -> VirtioGpuResult {
|
||||
let resource = self
|
||||
.resources
|
||||
.get_mut(&resource_id)
|
||||
.ok_or(ErrInvalidResourceId)?;
|
||||
|
||||
let Some(offset) = resource.blob_shmem_offset else {
|
||||
log::warn!(
|
||||
"Guest tried to unmap blob resource with resource_id={resource_id}, but it is not \
|
||||
mapped!"
|
||||
);
|
||||
return Err(ErrInvalidParameter);
|
||||
};
|
||||
|
||||
common_unmap_blob(&self.backend, resource.blob_size, offset)?;
|
||||
|
||||
resource.blob_shmem_offset = None;
|
||||
|
||||
Ok(OkNoData)
|
||||
}
|
||||
}
|
||||
|
||||
@ -732,6 +850,11 @@ mod gfx_fence_tests {
|
||||
GpuBackend::from_stream(backend)
|
||||
}
|
||||
|
||||
fn dummy_backend() -> Backend {
|
||||
let (_, backend) = UnixStream::pair().unwrap();
|
||||
Backend::from_stream(backend)
|
||||
}
|
||||
|
||||
/// Attempts to create a GPU adapter for testing.
|
||||
/// Returns None if gfxstream initialization fails (e.g., in CI without GPU
|
||||
/// drivers).
|
||||
@ -776,6 +899,7 @@ mod gfx_fence_tests {
|
||||
});
|
||||
|
||||
Some(GfxstreamAdapter {
|
||||
backend: dummy_backend(),
|
||||
gpu_backend: dummy_gpu_backend(),
|
||||
resources: BTreeMap::default(),
|
||||
fence_state,
|
||||
|
||||
@ -13,7 +13,7 @@ use vm_memory::{GuestAddress, GuestMemoryMmap, VolatileSlice};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
use crate::{
|
||||
gpu_types::{ResourceCreate3d, Transfer3DDesc, VirtioGpuRing},
|
||||
gpu_types::{ResourceCreate3d, ResourceCreateBlob, Transfer3DDesc, VirtioGpuRing},
|
||||
protocol::{virtio_gpu_rect, GpuResponse, VirtioGpuResult},
|
||||
renderer::Renderer,
|
||||
GpuConfig,
|
||||
@ -27,6 +27,7 @@ impl NullAdapter {
|
||||
pub fn new(
|
||||
_queue_ctl: &vhost_user_backend::VringRwLock,
|
||||
_config: &GpuConfig,
|
||||
_backend: vhost::vhost_user::Backend,
|
||||
gpu_backend: GpuBackend,
|
||||
) -> Self {
|
||||
trace!("NullAdapter created");
|
||||
@ -224,11 +225,9 @@ impl Renderer for NullAdapter {
|
||||
fn resource_create_blob(
|
||||
&mut self,
|
||||
_ctx_id: u32,
|
||||
_resource_id: u32,
|
||||
_blob_id: u64,
|
||||
_size: u64,
|
||||
_blob_mem: u32,
|
||||
_blob_flags: u32,
|
||||
_resource_create_blob: ResourceCreateBlob,
|
||||
_vecs: Vec<(vm_memory::GuestAddress, usize)>,
|
||||
_mem: &vm_memory::GuestMemoryMmap,
|
||||
) -> VirtioGpuResult {
|
||||
trace!("NullAdapter::resource_create_blob - no-op");
|
||||
Ok(GpuResponse::OkNoData)
|
||||
@ -256,15 +255,16 @@ mod tests {
|
||||
use crate::{GpuFlags, GpuMode};
|
||||
|
||||
fn create_null_adapter() -> NullAdapter {
|
||||
let (_, backend) = UnixStream::pair().unwrap();
|
||||
let gpu_backend = GpuBackend::from_stream(backend);
|
||||
let (stream1, stream2) = UnixStream::pair().unwrap();
|
||||
let backend = vhost::vhost_user::Backend::from_stream(stream1);
|
||||
let gpu_backend = GpuBackend::from_stream(stream2);
|
||||
let mem = GuestMemoryAtomic::new(
|
||||
GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(),
|
||||
);
|
||||
let vring = VringRwLock::new(mem, 0x100).unwrap();
|
||||
let config = GpuConfig::new(GpuMode::Null, None, GpuFlags::default()).unwrap();
|
||||
|
||||
NullAdapter::new(&vring, &config, gpu_backend)
|
||||
NullAdapter::new(&vring, &config, backend, gpu_backend)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -430,9 +430,21 @@ mod tests {
|
||||
#[test]
|
||||
fn test_null_adapter_blob_operations() {
|
||||
let mut adapter = create_null_adapter();
|
||||
let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
|
||||
|
||||
// Verify blob resource creation succeeds
|
||||
let result = adapter.resource_create_blob(0, 1, 1, 4096, 0, 0);
|
||||
let result = adapter.resource_create_blob(
|
||||
0,
|
||||
ResourceCreateBlob {
|
||||
resource_id: 1,
|
||||
blob_id: 1,
|
||||
blob_mem: 0,
|
||||
blob_flags: 0,
|
||||
size: 4096,
|
||||
},
|
||||
vec![],
|
||||
&mem,
|
||||
);
|
||||
assert!(matches!(result, Ok(GpuResponse::OkNoData)));
|
||||
|
||||
// Verify mapping blob resource succeeds
|
||||
|
||||
@ -4,53 +4,54 @@
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
|
||||
|
||||
use bitflags::Flags;
|
||||
use libc::c_void;
|
||||
use log::{debug, error, trace, warn};
|
||||
use rutabaga_gfx::RutabagaFence;
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
io::IoSliceMut,
|
||||
os::fd::{AsFd, FromRawFd, IntoRawFd, RawFd},
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use libc::c_void;
|
||||
use log::{debug, error, trace, warn};
|
||||
use rutabaga_gfx::RutabagaFence;
|
||||
use vhost::vhost_user::{
|
||||
gpu_message::{
|
||||
VhostUserGpuCursorPos, VhostUserGpuDMABUFScanout, VhostUserGpuDMABUFScanout2,
|
||||
VhostUserGpuEdidRequest, VhostUserGpuUpdate,
|
||||
},
|
||||
GpuBackend,
|
||||
message::VhostUserMMapFlags,
|
||||
Backend, GpuBackend,
|
||||
};
|
||||
use vhost_user_backend::{VringRwLock, VringT};
|
||||
use virglrenderer::{
|
||||
FenceHandler, Iovec, VirglContext, VirglRenderer, VirglRendererFlags, VirglResource,
|
||||
VIRGL_HANDLE_TYPE_MEM_DMABUF,
|
||||
FenceHandler, Iovec, VirglRenderer, VirglRendererFlags, VirglResource,
|
||||
VIRGL_HANDLE_TYPE_MEM_DMABUF, VIRGL_HANDLE_TYPE_MEM_OPAQUE_FD, VIRGL_MAP_CACHE_MASK,
|
||||
};
|
||||
use virtio_bindings::virtio_gpu::VIRTIO_GPU_BLOB_MEM_HOST3D;
|
||||
use vm_memory::{GuestAddress, GuestMemory, GuestMemoryMmap, VolatileSlice};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
use crate::{
|
||||
backend::{
|
||||
common,
|
||||
common::{common_set_scanout_disable, AssociatedScanouts, CursorConfig, VirtioGpuScanout},
|
||||
common::{
|
||||
common_map_blob, common_set_scanout_disable, common_unmap_blob, AssociatedScanouts,
|
||||
CursorConfig, VirtioGpuScanout,
|
||||
},
|
||||
},
|
||||
gpu_types::{FenceState, ResourceCreate3d, Transfer3DDesc, VirtioGpuRing},
|
||||
gpu_types::{FenceState, ResourceCreate3d, ResourceCreateBlob, Transfer3DDesc, VirtioGpuRing},
|
||||
protocol::{
|
||||
virtio_gpu_rect, GpuResponse,
|
||||
GpuResponse::{
|
||||
ErrInvalidContextId, ErrInvalidParameter, ErrInvalidResourceId, ErrInvalidScanoutId,
|
||||
ErrUnspec, OkCapset, OkCapsetInfo, OkNoData,
|
||||
ErrUnspec, OkCapset, OkCapsetInfo, OkMapInfo, OkNoData,
|
||||
},
|
||||
VirtioGpuResult, VIRTIO_GPU_MAX_SCANOUTS,
|
||||
},
|
||||
renderer::Renderer,
|
||||
GpuConfig,
|
||||
GpuCapset, GpuConfig,
|
||||
};
|
||||
|
||||
const CAPSET_ID_VIRGL: u32 = 1;
|
||||
const CAPSET_ID_VIRGL2: u32 = 2;
|
||||
const CAPSET_ID_VENUS: u32 = 4;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct GpuResource {
|
||||
pub virgl_resource: VirglResource,
|
||||
@ -58,6 +59,8 @@ pub struct GpuResource {
|
||||
// resource. Resource could be used for multiple scanouts.
|
||||
pub scanouts: AssociatedScanouts,
|
||||
pub backing_iovecs: Arc<Mutex<Option<Vec<Iovec>>>>,
|
||||
pub blob_size: u64,
|
||||
pub blob_shmem_offset: Option<u64>,
|
||||
}
|
||||
|
||||
fn sglist_to_iovecs(
|
||||
@ -134,18 +137,30 @@ impl FenceHandler for VirglFenceHandler {
|
||||
|
||||
pub struct VirglRendererAdapter {
|
||||
renderer: VirglRenderer,
|
||||
capsets: GpuCapset,
|
||||
#[allow(dead_code)]
|
||||
backend: Backend,
|
||||
gpu_backend: GpuBackend,
|
||||
fence_state: Arc<Mutex<FenceState>>,
|
||||
resources: BTreeMap<u32, GpuResource>,
|
||||
contexts: BTreeMap<u32, VirglContext>,
|
||||
scanouts: [Option<VirtioGpuScanout>; VIRTIO_GPU_MAX_SCANOUTS as usize],
|
||||
}
|
||||
|
||||
impl VirglRendererAdapter {
|
||||
pub fn new(queue_ctl: &VringRwLock, config: &GpuConfig, gpu_backend: GpuBackend) -> Self {
|
||||
pub fn new(
|
||||
queue_ctl: &VringRwLock,
|
||||
backend: Backend,
|
||||
config: &GpuConfig,
|
||||
gpu_backend: GpuBackend,
|
||||
) -> Self {
|
||||
let capsets = config.capsets();
|
||||
let venus_enabled = capsets.contains(GpuCapset::VENUS);
|
||||
let virgl_enabled = !(capsets & (GpuCapset::VIRGL | GpuCapset::VIRGL2)).is_empty();
|
||||
|
||||
let virglrenderer_flags = VirglRendererFlags::new()
|
||||
.use_virgl(true)
|
||||
.use_venus(true)
|
||||
.use_virgl(virgl_enabled)
|
||||
.use_venus(venus_enabled)
|
||||
.use_render_server(venus_enabled)
|
||||
.use_egl(config.flags().use_egl)
|
||||
.use_gles(config.flags().use_gles)
|
||||
.use_glx(config.flags().use_glx)
|
||||
@ -162,11 +177,12 @@ impl VirglRendererAdapter {
|
||||
let renderer = VirglRenderer::init(virglrenderer_flags, fence_handler, None)
|
||||
.expect("Failed to initialize virglrenderer");
|
||||
Self {
|
||||
capsets,
|
||||
renderer,
|
||||
backend,
|
||||
gpu_backend,
|
||||
fence_state,
|
||||
resources: BTreeMap::new(),
|
||||
contexts: BTreeMap::new(),
|
||||
scanouts: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -184,6 +200,8 @@ impl Renderer for VirglRendererAdapter {
|
||||
virgl_resource,
|
||||
scanouts: AssociatedScanouts::default(),
|
||||
backing_iovecs: Arc::new(Mutex::new(None)),
|
||||
blob_size: 0,
|
||||
blob_shmem_offset: None,
|
||||
};
|
||||
self.resources.insert(resource_id, local_resource);
|
||||
Ok(OkNoData)
|
||||
@ -320,13 +338,14 @@ impl Renderer for VirglRendererAdapter {
|
||||
}
|
||||
|
||||
fn get_capset_info(&self, index: u32) -> VirtioGpuResult {
|
||||
debug!("the capset index is {index}");
|
||||
let capset_id = match index {
|
||||
0 => CAPSET_ID_VIRGL,
|
||||
1 => CAPSET_ID_VIRGL2,
|
||||
3 => CAPSET_ID_VENUS,
|
||||
_ => return Err(ErrInvalidParameter),
|
||||
};
|
||||
debug!("Looking up capset at index {index}");
|
||||
let capset_id = self
|
||||
.capsets
|
||||
.iter()
|
||||
.nth(index as usize)
|
||||
.ok_or(ErrInvalidParameter)?
|
||||
.bits() as u32;
|
||||
|
||||
let (version, size) = self.renderer.get_capset_info(index);
|
||||
Ok(OkCapsetInfo {
|
||||
capset_id,
|
||||
@ -346,41 +365,34 @@ impl Renderer for VirglRendererAdapter {
|
||||
context_init: u32,
|
||||
context_name: Option<&str>,
|
||||
) -> VirtioGpuResult {
|
||||
if self.contexts.contains_key(&ctx_id) {
|
||||
return Err(ErrUnspec);
|
||||
}
|
||||
trace!("Creating context ctx_id={ctx_id}, '{context_name:?}', context_init={context_init}");
|
||||
|
||||
// Create the VirglContext using virglrenderer
|
||||
let ctx = virglrenderer::VirglContext::create_context(ctx_id, context_init, context_name)
|
||||
// Create the context using virglrenderer (contexts are now managed internally)
|
||||
self.renderer
|
||||
.create_context(ctx_id, context_init, context_name)
|
||||
.map_err(|_| ErrInvalidContextId)?;
|
||||
|
||||
// Insert the newly created context into our local BTreeMap.
|
||||
self.contexts.insert(ctx_id, ctx);
|
||||
Ok(OkNoData)
|
||||
}
|
||||
|
||||
fn destroy_context(&mut self, ctx_id: u32) -> VirtioGpuResult {
|
||||
self.contexts.remove(&ctx_id).ok_or(ErrInvalidContextId)?;
|
||||
self.renderer.destroy_context(ctx_id);
|
||||
Ok(OkNoData)
|
||||
}
|
||||
|
||||
fn context_attach_resource(&mut self, ctx_id: u32, resource_id: u32) -> VirtioGpuResult {
|
||||
let ctx = self.contexts.get_mut(&ctx_id).ok_or(ErrInvalidContextId)?;
|
||||
let resource = self
|
||||
.resources
|
||||
.get_mut(&resource_id)
|
||||
.ok_or(ErrInvalidResourceId)?;
|
||||
ctx.attach(&mut resource.virgl_resource);
|
||||
if !self.resources.contains_key(&resource_id) {
|
||||
return Err(ErrInvalidResourceId);
|
||||
}
|
||||
self.renderer.ctx_attach_resource(ctx_id, resource_id);
|
||||
Ok(OkNoData)
|
||||
}
|
||||
|
||||
fn context_detach_resource(&mut self, ctx_id: u32, resource_id: u32) -> VirtioGpuResult {
|
||||
let ctx = self.contexts.get_mut(&ctx_id).ok_or(ErrInvalidContextId)?;
|
||||
let resource = self
|
||||
.resources
|
||||
.get_mut(&resource_id)
|
||||
.ok_or(ErrInvalidResourceId)?;
|
||||
ctx.detach(&resource.virgl_resource);
|
||||
if !self.resources.contains_key(&resource_id) {
|
||||
return Err(ErrInvalidResourceId);
|
||||
}
|
||||
self.renderer.ctx_detach_resource(ctx_id, resource_id);
|
||||
Ok(OkNoData)
|
||||
}
|
||||
|
||||
@ -390,9 +402,8 @@ impl Renderer for VirglRendererAdapter {
|
||||
commands: &mut [u8],
|
||||
fence_ids: &[u64],
|
||||
) -> VirtioGpuResult {
|
||||
let ctx = self.contexts.get_mut(&ctx_id).ok_or(ErrInvalidContextId)?;
|
||||
|
||||
ctx.submit_cmd(commands, fence_ids)
|
||||
self.renderer
|
||||
.submit_cmd(ctx_id, commands, fence_ids)
|
||||
.map(|()| OkNoData)
|
||||
.map_err(|_| ErrUnspec)
|
||||
}
|
||||
@ -612,25 +623,112 @@ impl Renderer for VirglRendererAdapter {
|
||||
|
||||
fn resource_create_blob(
|
||||
&mut self,
|
||||
_ctx_id: u32,
|
||||
_resource_id: u32,
|
||||
_blob_id: u64,
|
||||
_size: u64,
|
||||
_blob_mem: u32,
|
||||
_blob_flags: u32,
|
||||
ctx_id: u32,
|
||||
resource_create_blob: ResourceCreateBlob,
|
||||
vecs: Vec<(GuestAddress, usize)>,
|
||||
mem: &GuestMemoryMmap,
|
||||
) -> VirtioGpuResult {
|
||||
error!("Not implemented: resource_create_blob");
|
||||
Err(ErrUnspec)
|
||||
let mut virgl_iovecs = None;
|
||||
|
||||
if resource_create_blob.blob_flags
|
||||
& crate::protocol::VIRTIO_GPU_BLOB_FLAG_CREATE_GUEST_HANDLE
|
||||
!= 0
|
||||
{
|
||||
error!("GUEST_HANDLE unimplemented for virgl backend");
|
||||
return Err(ErrUnspec);
|
||||
} else if resource_create_blob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D {
|
||||
virgl_iovecs = Some(sglist_to_iovecs(&vecs[..], mem).map_err(|_| ErrUnspec)?);
|
||||
}
|
||||
|
||||
let virgl_resource = self
|
||||
.renderer
|
||||
.create_blob(
|
||||
ctx_id,
|
||||
0, // width
|
||||
0, // height
|
||||
resource_create_blob.resource_id,
|
||||
resource_create_blob.into(),
|
||||
virgl_iovecs.as_deref(),
|
||||
)
|
||||
.map_err(|_| ErrUnspec)?;
|
||||
|
||||
let resource = GpuResource {
|
||||
virgl_resource,
|
||||
scanouts: AssociatedScanouts::default(),
|
||||
backing_iovecs: Arc::new(Mutex::new(virgl_iovecs)),
|
||||
blob_size: resource_create_blob.size,
|
||||
blob_shmem_offset: None,
|
||||
};
|
||||
|
||||
debug_assert!(
|
||||
!self
|
||||
.resources
|
||||
.contains_key(&resource_create_blob.resource_id),
|
||||
"Resource ID {} already exists in the resources map.",
|
||||
resource_create_blob.resource_id
|
||||
);
|
||||
|
||||
self.resources
|
||||
.insert(resource_create_blob.resource_id, resource);
|
||||
Ok(OkNoData)
|
||||
}
|
||||
|
||||
fn resource_map_blob(&mut self, _resource_id: u32, _offset: u64) -> VirtioGpuResult {
|
||||
error!("Not implemented: resource_map_blob");
|
||||
Err(ErrUnspec)
|
||||
fn resource_map_blob(&mut self, resource_id: u32, offset: u64) -> VirtioGpuResult {
|
||||
let resource = self
|
||||
.resources
|
||||
.get_mut(&resource_id)
|
||||
.ok_or(ErrInvalidResourceId)?;
|
||||
|
||||
let map_info = resource.virgl_resource.map_info.ok_or(ErrUnspec)?;
|
||||
|
||||
let handle = resource.virgl_resource.handle.as_ref().ok_or(ErrUnspec)?;
|
||||
|
||||
// Check handle type - we don't support OPAQUE_FD mapping
|
||||
if handle.handle_type == VIRGL_HANDLE_TYPE_MEM_OPAQUE_FD {
|
||||
error!("VIRGL_HANDLE_TYPE_MEM_OPAQUE_FD not supported for mapping");
|
||||
return Err(ErrUnspec);
|
||||
}
|
||||
|
||||
// virgl doesn't provide detailed permissions for mapping, map everything as
|
||||
// writable
|
||||
let flags = VhostUserMMapFlags::WRITABLE;
|
||||
|
||||
common_map_blob(
|
||||
&self.backend,
|
||||
flags,
|
||||
&handle.os_handle.as_fd(),
|
||||
resource.blob_size,
|
||||
offset,
|
||||
resource_id,
|
||||
)?;
|
||||
|
||||
resource.blob_shmem_offset = Some(offset);
|
||||
|
||||
// Return cache flags only (access flags not part of virtio-gpu spec)
|
||||
Ok(OkMapInfo {
|
||||
map_info: map_info & VIRGL_MAP_CACHE_MASK,
|
||||
})
|
||||
}
|
||||
|
||||
fn resource_unmap_blob(&mut self, _resource_id: u32) -> VirtioGpuResult {
|
||||
error!("Not implemented: resource_unmap_blob");
|
||||
Err(ErrUnspec)
|
||||
fn resource_unmap_blob(&mut self, resource_id: u32) -> VirtioGpuResult {
|
||||
let resource = self
|
||||
.resources
|
||||
.get_mut(&resource_id)
|
||||
.ok_or(ErrInvalidResourceId)?;
|
||||
|
||||
let Some(offset) = resource.blob_shmem_offset else {
|
||||
warn!(
|
||||
"Guest tried to unmap blob resource with resource_id={resource_id}, but it is not \
|
||||
mapped!"
|
||||
);
|
||||
return Err(ErrInvalidParameter);
|
||||
};
|
||||
|
||||
common_unmap_blob(&self.backend, resource.blob_size, offset)?;
|
||||
|
||||
resource.blob_shmem_offset = None;
|
||||
|
||||
Ok(OkNoData)
|
||||
}
|
||||
}
|
||||
|
||||
@ -648,7 +746,10 @@ mod virgl_cov_tests {
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
gpu_types::{FenceDescriptor, FenceState, ResourceCreate3d, Transfer3DDesc, VirtioGpuRing},
|
||||
gpu_types::{
|
||||
FenceDescriptor, FenceState, ResourceCreate3d, ResourceCreateBlob, Transfer3DDesc,
|
||||
VirtioGpuRing,
|
||||
},
|
||||
protocol::{virtio_gpu_rect, GpuResponse, VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM},
|
||||
renderer::Renderer,
|
||||
testutils::{
|
||||
@ -672,6 +773,11 @@ mod virgl_cov_tests {
|
||||
GpuBackend::from_stream(backend)
|
||||
}
|
||||
|
||||
fn dummy_backend() -> Backend {
|
||||
let (_, backend) = UnixStream::pair().unwrap();
|
||||
Backend::from_stream(backend)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sglist_to_iovecs_err_on_invalid_slice() {
|
||||
// Single region: 0x1000..0x2000 (4 KiB)
|
||||
@ -744,10 +850,12 @@ mod virgl_cov_tests {
|
||||
}
|
||||
assert!(call_b.read().is_err(), "no signal when no match");
|
||||
|
||||
let capsets = GpuCapset::VIRGL | GpuCapset::VIRGL2;
|
||||
|
||||
// Initialize virgl ONCE in this forked process; exercise adapter paths
|
||||
let cfg = GpuConfig::new(
|
||||
GpuMode::VirglRenderer,
|
||||
Some(GpuCapset::VIRGL | GpuCapset::VIRGL2),
|
||||
Some(capsets),
|
||||
GpuFlags::default(),
|
||||
).expect("GpuConfig");
|
||||
|
||||
@ -757,8 +865,9 @@ mod virgl_cov_tests {
|
||||
let (vring, _outs, _call_evt) =
|
||||
create_vring(&mem, &[] as &[TestingDescChainArgs], GuestAddress(0x2000), GuestAddress(0x4000), 64);
|
||||
|
||||
let backend = dummy_gpu_backend();
|
||||
let mut gpu = VirglRendererAdapter::new(&vring, &cfg, backend);
|
||||
let backend = dummy_backend();
|
||||
let gpu_backend = dummy_gpu_backend();
|
||||
let mut gpu = VirglRendererAdapter::new(&vring, backend, &cfg, gpu_backend);
|
||||
|
||||
gpu.event_poll();
|
||||
let edid_req = VhostUserGpuEdidRequest {
|
||||
@ -862,22 +971,34 @@ mod virgl_cov_tests {
|
||||
assert_matches!(gpu.flush_resource(0, dirty), Ok(GpuResponse::OkNoData));
|
||||
|
||||
// Test capset queries
|
||||
for index in [0, 1, 3] {
|
||||
for index in 0..capsets.num_capsets() {
|
||||
test_capset_operations(&gpu, index);
|
||||
}
|
||||
|
||||
// Test blob resource functions (all should return ErrUnspec - not implemented)
|
||||
// Test blob resource functions
|
||||
assert_matches!(
|
||||
gpu.resource_create_blob(1, 100, 0, 4096, 0, 0),
|
||||
gpu.resource_create_blob(
|
||||
1,
|
||||
ResourceCreateBlob {
|
||||
resource_id: 100,
|
||||
blob_id: 0,
|
||||
blob_mem: 0,
|
||||
blob_flags: 0,
|
||||
size: 4096,
|
||||
},
|
||||
vec![],
|
||||
&gm_back
|
||||
),
|
||||
Err(GpuResponse::ErrUnspec)
|
||||
);
|
||||
// resource 100 was never created, so these return ErrInvalidResourceId
|
||||
assert_matches!(
|
||||
gpu.resource_map_blob(100, 0),
|
||||
Err(GpuResponse::ErrUnspec)
|
||||
Err(GpuResponse::ErrInvalidResourceId)
|
||||
);
|
||||
assert_matches!(
|
||||
gpu.resource_unmap_blob(100),
|
||||
Err(GpuResponse::ErrUnspec)
|
||||
Err(GpuResponse::ErrInvalidResourceId)
|
||||
);
|
||||
|
||||
// Test resource_assign_uuid (not implemented)
|
||||
|
||||
@ -22,9 +22,10 @@ macro_rules! handle_adapter {
|
||||
Some(renderer) => renderer,
|
||||
None => {
|
||||
// Pass $vrings to the call
|
||||
let (control_vring, gpu_backend) = $self.extract_backend_and_vring($vrings)?;
|
||||
let (control_vring, backend, gpu_backend) =
|
||||
$self.extract_backend_and_vring($vrings)?;
|
||||
|
||||
let renderer = $new_adapter(control_vring, gpu_backend);
|
||||
let renderer = $new_adapter(control_vring, backend, gpu_backend);
|
||||
|
||||
event_poll_fd = renderer.get_event_poll_fd();
|
||||
maybe_renderer.insert(renderer)
|
||||
@ -52,7 +53,7 @@ use thiserror::Error as ThisError;
|
||||
use vhost::vhost_user::{
|
||||
gpu_message::{VhostUserGpuCursorPos, VhostUserGpuEdidRequest},
|
||||
message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures},
|
||||
GpuBackend,
|
||||
Backend, GpuBackend,
|
||||
};
|
||||
use vhost_user_backend::{VhostUserBackend, VringEpollHandler, VringRwLock, VringT};
|
||||
use virtio_bindings::{
|
||||
@ -79,7 +80,7 @@ use crate::backend::gfxstream::GfxstreamAdapter;
|
||||
use crate::backend::virgl::VirglRendererAdapter;
|
||||
use crate::{
|
||||
backend::null::NullAdapter,
|
||||
gpu_types::{ResourceCreate3d, Transfer3DDesc, VirtioGpuRing},
|
||||
gpu_types::{ResourceCreate3d, ResourceCreateBlob, Transfer3DDesc, VirtioGpuRing},
|
||||
protocol::{
|
||||
virtio_gpu_ctrl_hdr, virtio_gpu_ctx_create, virtio_gpu_get_edid,
|
||||
virtio_gpu_resource_create_2d, virtio_gpu_resource_create_3d, virtio_gpu_transfer_host_3d,
|
||||
@ -140,6 +141,7 @@ impl From<Error> for io::Error {
|
||||
struct VhostUserGpuBackendInner {
|
||||
virtio_cfg: VirtioGpuConfig,
|
||||
event_idx_enabled: bool,
|
||||
backend: Option<Backend>,
|
||||
gpu_backend: Option<GpuBackend>,
|
||||
exit_consumer: EventConsumer,
|
||||
exit_notifier: EventNotifier,
|
||||
@ -173,6 +175,7 @@ impl VhostUserGpuBackend {
|
||||
num_capsets: Le32::from(gpu_config.capsets().num_capsets()),
|
||||
},
|
||||
event_idx_enabled: false,
|
||||
backend: None,
|
||||
gpu_backend: None,
|
||||
exit_consumer,
|
||||
exit_notifier,
|
||||
@ -257,18 +260,27 @@ impl VhostUserGpuBackendInner {
|
||||
fence_ids,
|
||||
mut cmd_data,
|
||||
} => renderer.submit_command(hdr.ctx_id.into(), &mut cmd_data, &fence_ids),
|
||||
GpuCommand::ResourceCreateBlob(_) => {
|
||||
panic!("virtio_gpu: GpuCommand::ResourceCreateBlob unimplemented")
|
||||
}
|
||||
GpuCommand::ResourceCreateBlob(info, vecs) => renderer.resource_create_blob(
|
||||
hdr.ctx_id.into(),
|
||||
ResourceCreateBlob {
|
||||
resource_id: info.resource_id.into(),
|
||||
blob_id: info.blob_id.into(),
|
||||
blob_mem: info.blob_mem.into(),
|
||||
blob_flags: info.blob_flags.into(),
|
||||
size: info.size.into(),
|
||||
},
|
||||
vecs,
|
||||
mem,
|
||||
),
|
||||
|
||||
GpuCommand::SetScanoutBlob(_) => {
|
||||
panic!("virtio_gpu: GpuCommand::SetScanoutBlob unimplemented")
|
||||
}
|
||||
GpuCommand::ResourceMapBlob(_) => {
|
||||
panic!("virtio_gpu: GpuCommand::ResourceMapBlob unimplemented")
|
||||
GpuCommand::ResourceMapBlob(info) => {
|
||||
renderer.resource_map_blob(info.resource_id.into(), info.offset.into())
|
||||
}
|
||||
GpuCommand::ResourceUnmapBlob(_) => {
|
||||
panic!("virtio_gpu: GpuCommand::ResourceUnmapBlob unimplemented")
|
||||
GpuCommand::ResourceUnmapBlob(info) => {
|
||||
renderer.resource_unmap_blob(info.resource_id.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -347,11 +359,11 @@ impl VhostUserGpuBackendInner {
|
||||
hdr: virtio_gpu_ctrl_hdr,
|
||||
req: virtio_gpu_ctx_create,
|
||||
) -> VirtioGpuResult {
|
||||
let context_name: Option<String> = Some(req.get_debug_name());
|
||||
let context_name = req.get_debug_name();
|
||||
renderer.create_context(
|
||||
hdr.ctx_id.into(),
|
||||
req.context_init.into(),
|
||||
context_name.as_deref(),
|
||||
Some(&context_name),
|
||||
)
|
||||
}
|
||||
|
||||
@ -592,13 +604,17 @@ impl VhostUserGpuBackendInner {
|
||||
fn extract_backend_and_vring<'a>(
|
||||
&mut self,
|
||||
vrings: &'a [VringRwLock],
|
||||
) -> IoResult<(&'a VringRwLock, GpuBackend)> {
|
||||
) -> IoResult<(&'a VringRwLock, Backend, GpuBackend)> {
|
||||
let control_vring = &vrings[CONTROL_QUEUE as usize];
|
||||
let backend = self
|
||||
.backend
|
||||
.take()
|
||||
.ok_or_else(|| io::Error::other("set_backend_req_fd() not called, Backend missing"))?;
|
||||
let gpu_backend = self
|
||||
.gpu_backend
|
||||
.take()
|
||||
.ok_or_else(|| io::Error::other("set_gpu_socket() not called, GpuBackend missing"))?;
|
||||
Ok((control_vring, backend))
|
||||
Ok((control_vring, backend, gpu_backend))
|
||||
}
|
||||
|
||||
fn lazy_init_and_handle_event(
|
||||
@ -618,8 +634,8 @@ impl VhostUserGpuBackendInner {
|
||||
GpuMode::Gfxstream => handle_adapter!(
|
||||
GfxstreamAdapter,
|
||||
TLS_GFXSTREAM,
|
||||
|control_vring, gpu_backend| {
|
||||
GfxstreamAdapter::new(control_vring, &self.gpu_config, gpu_backend)
|
||||
|control_vring, backend, gpu_backend| {
|
||||
GfxstreamAdapter::new(control_vring, backend, &self.gpu_config, gpu_backend)
|
||||
},
|
||||
self,
|
||||
device_event,
|
||||
@ -630,8 +646,8 @@ impl VhostUserGpuBackendInner {
|
||||
GpuMode::VirglRenderer => handle_adapter!(
|
||||
VirglRendererAdapter,
|
||||
TLS_VIRGL,
|
||||
|control_vring, gpu_backend| {
|
||||
VirglRendererAdapter::new(control_vring, &self.gpu_config, gpu_backend)
|
||||
|control_vring, backend, gpu_backend| {
|
||||
VirglRendererAdapter::new(control_vring, backend, &self.gpu_config, gpu_backend)
|
||||
},
|
||||
self,
|
||||
device_event,
|
||||
@ -641,8 +657,8 @@ impl VhostUserGpuBackendInner {
|
||||
GpuMode::Null => handle_adapter!(
|
||||
NullAdapter,
|
||||
TLS_NULL,
|
||||
|control_vring, gpu_backend| {
|
||||
NullAdapter::new(control_vring, &self.gpu_config, gpu_backend)
|
||||
|control_vring, backend, gpu_backend| {
|
||||
NullAdapter::new(control_vring, &self.gpu_config, backend, gpu_backend)
|
||||
},
|
||||
self,
|
||||
device_event,
|
||||
@ -695,7 +711,11 @@ impl VhostUserBackend for VhostUserGpuBackend {
|
||||
|
||||
fn protocol_features(&self) -> VhostUserProtocolFeatures {
|
||||
debug!("Protocol features called");
|
||||
VhostUserProtocolFeatures::CONFIG | VhostUserProtocolFeatures::MQ
|
||||
VhostUserProtocolFeatures::CONFIG
|
||||
| VhostUserProtocolFeatures::MQ
|
||||
| VhostUserProtocolFeatures::BACKEND_REQ
|
||||
| VhostUserProtocolFeatures::BACKEND_SEND_FD
|
||||
| VhostUserProtocolFeatures::SHMEM
|
||||
}
|
||||
|
||||
fn set_event_idx(&self, enabled: bool) {
|
||||
@ -709,6 +729,11 @@ impl VhostUserBackend for VhostUserGpuBackend {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_backend_req_fd(&self, backend: Backend) {
|
||||
trace!("Got set_backend_req_fd");
|
||||
self.inner.lock().unwrap().backend = Some(backend);
|
||||
}
|
||||
|
||||
fn set_gpu_socket(&self, backend: GpuBackend) -> IoResult<()> {
|
||||
self.inner.lock().unwrap().gpu_backend = Some(backend);
|
||||
Ok(())
|
||||
@ -787,7 +812,7 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
gpu_types::{ResourceCreate3d, Transfer3DDesc, VirtioGpuRing},
|
||||
gpu_types::{ResourceCreate3d, ResourceCreateBlob, Transfer3DDesc, VirtioGpuRing},
|
||||
protocol::{
|
||||
virtio_gpu_ctrl_hdr, virtio_gpu_ctx_create, virtio_gpu_ctx_destroy,
|
||||
virtio_gpu_ctx_resource, virtio_gpu_get_capset, virtio_gpu_get_capset_info,
|
||||
@ -821,11 +846,9 @@ mod tests {
|
||||
fn resource_create_blob(
|
||||
&mut self,
|
||||
ctx_id: u32,
|
||||
resource_id: u32,
|
||||
blob_id: u64,
|
||||
size: u64,
|
||||
blob_mem: u32,
|
||||
blob_flags: u32,
|
||||
resource_create_blob: ResourceCreateBlob,
|
||||
vecs: Vec<(GuestAddress, usize)>,
|
||||
mem: &GuestMemoryMmap,
|
||||
) -> VirtioGpuResult;
|
||||
fn resource_map_blob(&mut self, resource_id: u32, offset: u64) -> VirtioGpuResult;
|
||||
fn resource_unmap_blob(&mut self, resource_id: u32) -> VirtioGpuResult;
|
||||
@ -917,6 +940,11 @@ mod tests {
|
||||
(frontend, backend)
|
||||
}
|
||||
|
||||
fn dummy_backend_request_socket() -> Backend {
|
||||
let (_frontend, backend) = UnixStream::pair().unwrap();
|
||||
Backend::from_stream(backend)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_gpu_command() {
|
||||
let (_, mem) = init();
|
||||
@ -1398,7 +1426,11 @@ mod tests {
|
||||
assert_eq!(backend.features(), 0x0101_7100_001B);
|
||||
assert_eq!(
|
||||
backend.protocol_features(),
|
||||
VhostUserProtocolFeatures::CONFIG | VhostUserProtocolFeatures::MQ
|
||||
VhostUserProtocolFeatures::CONFIG
|
||||
| VhostUserProtocolFeatures::MQ
|
||||
| VhostUserProtocolFeatures::BACKEND_REQ
|
||||
| VhostUserProtocolFeatures::BACKEND_SEND_FD
|
||||
| VhostUserProtocolFeatures::SHMEM
|
||||
);
|
||||
assert_eq!(backend.queues_per_thread(), vec![0xffff_ffff]);
|
||||
assert_eq!(backend.get_config(0, 0), Vec::<u8>::new());
|
||||
@ -1420,7 +1452,7 @@ mod tests {
|
||||
let vring = VringRwLock::new(mem, 0x1000).unwrap();
|
||||
vring.set_queue_info(0x100, 0x200, 0x300).unwrap();
|
||||
vring.set_queue_ready(true);
|
||||
|
||||
backend.set_backend_req_fd(dummy_backend_request_socket());
|
||||
assert_eq!(
|
||||
backend
|
||||
.handle_event(0, EventSet::OUT, &[vring.clone()], 0)
|
||||
@ -1439,6 +1471,7 @@ mod tests {
|
||||
|
||||
// Hit the loop part
|
||||
backend.set_event_idx(true);
|
||||
backend.set_backend_req_fd(dummy_backend_request_socket());
|
||||
backend
|
||||
.handle_event(0, EventSet::IN, &[vring.clone()], 0)
|
||||
.unwrap();
|
||||
@ -1541,6 +1574,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
backend.set_gpu_socket(gpu_backend).unwrap();
|
||||
backend.set_backend_req_fd(dummy_backend_request_socket());
|
||||
|
||||
// Unfortunately, there is no way to create a VringEpollHandler directly (the ::new is not public)
|
||||
// So we create a daemon to create the epoll handler for us here
|
||||
|
||||
@ -48,6 +48,22 @@ macro_rules! impl_from_resource_create3d {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "backend-virgl", feature = "backend-gfxstream"))]
|
||||
macro_rules! impl_from_resource_create_blob {
|
||||
($target:ty) => {
|
||||
impl From<ResourceCreateBlob> for $target {
|
||||
fn from(r: ResourceCreateBlob) -> Self {
|
||||
Self {
|
||||
blob_id: r.blob_id,
|
||||
blob_mem: r.blob_mem,
|
||||
blob_flags: r.blob_flags,
|
||||
size: r.size,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
use std::{collections::BTreeMap, os::raw::c_void};
|
||||
|
||||
#[cfg(feature = "backend-gfxstream")]
|
||||
@ -147,6 +163,21 @@ impl_from_resource_create3d!(rutabaga_gfx::ResourceCreate3D);
|
||||
#[cfg(feature = "backend-virgl")]
|
||||
impl_from_resource_create3d!(virglrenderer::ResourceCreate3D);
|
||||
|
||||
#[cfg(feature = "backend-gfxstream")]
|
||||
impl_from_resource_create_blob!(rutabaga_gfx::ResourceCreateBlob);
|
||||
#[cfg(feature = "backend-virgl")]
|
||||
impl_from_resource_create_blob!(virglrenderer::ResourceCreateBlob);
|
||||
|
||||
/// Parameters for creating a blob resource.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ResourceCreateBlob {
|
||||
pub resource_id: u32,
|
||||
pub blob_id: u64,
|
||||
pub blob_mem: u32,
|
||||
pub blob_flags: u32,
|
||||
pub size: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ResourceCreate2d {
|
||||
pub resource_id: u32,
|
||||
|
||||
@ -30,7 +30,7 @@ use log::info;
|
||||
#[cfg(feature = "backend-gfxstream")]
|
||||
use rutabaga_gfx::{RUTABAGA_CAPSET_GFXSTREAM_GLES, RUTABAGA_CAPSET_GFXSTREAM_VULKAN};
|
||||
#[cfg(feature = "backend-virgl")]
|
||||
use rutabaga_gfx::{RUTABAGA_CAPSET_VIRGL, RUTABAGA_CAPSET_VIRGL2};
|
||||
use rutabaga_gfx::{RUTABAGA_CAPSET_VENUS, RUTABAGA_CAPSET_VIRGL, RUTABAGA_CAPSET_VIRGL2};
|
||||
use thiserror::Error as ThisError;
|
||||
use vhost_user_backend::VhostUserDaemon;
|
||||
use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};
|
||||
@ -68,7 +68,9 @@ bitflags! {
|
||||
#[cfg(feature = "backend-virgl")]
|
||||
const VIRGL2 = 1 << RUTABAGA_CAPSET_VIRGL2 as u64;
|
||||
#[cfg(feature = "backend-virgl")]
|
||||
const ALL_VIRGLRENDERER_CAPSETS = Self::VIRGL.bits() | Self::VIRGL2.bits();
|
||||
const VENUS = 1 << RUTABAGA_CAPSET_VENUS as u64;
|
||||
#[cfg(feature = "backend-virgl")]
|
||||
const ALL_VIRGLRENDERER_CAPSETS = Self::VIRGL.bits() | Self::VIRGL2.bits() | Self::VENUS.bits();
|
||||
|
||||
#[cfg(feature = "backend-gfxstream")]
|
||||
const GFXSTREAM_VULKAN = 1 << RUTABAGA_CAPSET_GFXSTREAM_VULKAN as u64;
|
||||
@ -98,6 +100,8 @@ impl Display for GpuCapset {
|
||||
Self::VIRGL => write!(f, "virgl")?,
|
||||
#[cfg(feature = "backend-virgl")]
|
||||
Self::VIRGL2 => write!(f, "virgl2")?,
|
||||
#[cfg(feature = "backend-virgl")]
|
||||
Self::VENUS => write!(f, "venus")?,
|
||||
#[cfg(feature = "backend-gfxstream")]
|
||||
Self::GFXSTREAM_VULKAN => write!(f, "gfxstream-vulkan")?,
|
||||
#[cfg(feature = "backend-gfxstream")]
|
||||
@ -334,7 +338,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_default_num_capsets() {
|
||||
#[cfg(feature = "backend-virgl")]
|
||||
assert_eq!(GpuConfig::DEFAULT_VIRGLRENDER_CAPSET_MASK.num_capsets(), 2);
|
||||
assert_eq!(GpuConfig::DEFAULT_VIRGLRENDER_CAPSET_MASK.num_capsets(), 3);
|
||||
#[cfg(feature = "backend-gfxstream")]
|
||||
assert_eq!(GpuConfig::DEFAULT_GFXSTREAM_CAPSET_MASK.num_capsets(), 2);
|
||||
}
|
||||
|
||||
@ -24,6 +24,10 @@ pub enum CapsetName {
|
||||
#[cfg(feature = "backend-virgl")]
|
||||
Virgl2 = GpuCapset::VIRGL2.bits(),
|
||||
|
||||
/// [virglrenderer] Venus (Vulkan) implementation
|
||||
#[cfg(feature = "backend-virgl")]
|
||||
Venus = GpuCapset::VENUS.bits(),
|
||||
|
||||
/// [gfxstream] Vulkan implementation (partial support only){n}
|
||||
/// NOTE: Can only be used for 2D display output for now, there is no
|
||||
/// hardware acceleration yet
|
||||
|
||||
@ -6,9 +6,9 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
cmp::min,
|
||||
convert::From,
|
||||
ffi::CStr,
|
||||
fmt::{self, Display},
|
||||
io::{self, Read, Write},
|
||||
marker::PhantomData,
|
||||
@ -441,14 +441,9 @@ impl Default for virtio_gpu_ctx_create {
|
||||
}
|
||||
|
||||
impl virtio_gpu_ctx_create {
|
||||
pub fn get_debug_name(&self) -> String {
|
||||
CStr::from_bytes_with_nul(
|
||||
&self.debug_name[..min(64, <Le32 as Into<u32>>::into(self.nlen) as usize)],
|
||||
)
|
||||
.map_or_else(
|
||||
|err| format!("Err({err})"),
|
||||
|c_str| c_str.to_string_lossy().into_owned(),
|
||||
)
|
||||
pub fn get_debug_name(&self) -> Cow<'_, str> {
|
||||
let len = min(64, <Le32 as Into<u32>>::into(self.nlen) as usize);
|
||||
String::from_utf8_lossy(&self.debug_name[..len])
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for virtio_gpu_ctx_create {
|
||||
@ -707,7 +702,7 @@ pub enum GpuCommand {
|
||||
cmd_data: Vec<u8>,
|
||||
fence_ids: Vec<u64>,
|
||||
},
|
||||
ResourceCreateBlob(virtio_gpu_resource_create_blob),
|
||||
ResourceCreateBlob(virtio_gpu_resource_create_blob, Vec<(GuestAddress, usize)>),
|
||||
ResourceMapBlob(virtio_gpu_resource_map_blob),
|
||||
ResourceUnmapBlob(virtio_gpu_resource_unmap_blob),
|
||||
UpdateCursor(virtio_gpu_update_cursor),
|
||||
@ -753,6 +748,23 @@ impl fmt::Debug for GpuCommand {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_mem_entries(
|
||||
reader: &mut Reader,
|
||||
num_entries: u32,
|
||||
) -> Result<Vec<(GuestAddress, usize)>, GpuCommandDecodeError> {
|
||||
let mut entries = Vec::with_capacity(num_entries as usize);
|
||||
|
||||
for _ in 0..num_entries {
|
||||
let entry: virtio_gpu_mem_entry =
|
||||
reader.read_obj().map_err(|_| Error::DescriptorReadFailed)?;
|
||||
entries.push((
|
||||
GuestAddress(entry.addr.into()),
|
||||
entry.length.to_native() as usize,
|
||||
))
|
||||
}
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
impl GpuCommand {
|
||||
pub const fn command_name(&self) -> &'static str {
|
||||
use GpuCommand::*;
|
||||
@ -777,7 +789,7 @@ impl GpuCommand {
|
||||
TransferToHost3d(_info) => "TransferToHost3d",
|
||||
TransferFromHost3d(_info) => "TransferFromHost3d",
|
||||
CmdSubmit3d { .. } => "CmdSubmit3d",
|
||||
ResourceCreateBlob(_info) => "ResourceCreateBlob",
|
||||
ResourceCreateBlob(_info, _) => "ResourceCreateBlob",
|
||||
ResourceMapBlob(_info) => "ResourceMapBlob",
|
||||
ResourceUnmapBlob(_info) => "ResourceUnmapBlob",
|
||||
UpdateCursor(_info) => "UpdateCursor",
|
||||
@ -824,16 +836,7 @@ impl GpuCommand {
|
||||
VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING => {
|
||||
let info: virtio_gpu_resource_attach_backing =
|
||||
reader.read_obj().map_err(|_| Error::DescriptorReadFailed)?;
|
||||
let mut entries =
|
||||
Vec::with_capacity(<Le32 as Into<u32>>::into(info.nr_entries) as usize);
|
||||
for _ in 0..info.nr_entries.into() {
|
||||
let entry: virtio_gpu_mem_entry =
|
||||
reader.read_obj().map_err(|_| Error::DescriptorReadFailed)?;
|
||||
entries.push((
|
||||
GuestAddress(entry.addr.into()),
|
||||
<Le32 as Into<u32>>::into(entry.length) as usize,
|
||||
));
|
||||
}
|
||||
let entries = read_mem_entries(reader, info.nr_entries.into())?;
|
||||
ResourceAttachBacking(info, entries)
|
||||
}
|
||||
VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING => {
|
||||
@ -891,7 +894,11 @@ impl GpuCommand {
|
||||
}
|
||||
}
|
||||
VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB => {
|
||||
ResourceCreateBlob(reader.read_obj().map_err(|_| Error::DescriptorReadFailed)?)
|
||||
let info: virtio_gpu_resource_create_blob =
|
||||
reader.read_obj().map_err(|_| Error::DescriptorReadFailed)?;
|
||||
|
||||
let entries = read_mem_entries(reader, info.nr_entries.into())?;
|
||||
ResourceCreateBlob(info, entries)
|
||||
}
|
||||
VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB => {
|
||||
ResourceMapBlob(reader.read_obj().map_err(|_| Error::DescriptorReadFailed)?)
|
||||
@ -1311,7 +1318,7 @@ mod tests {
|
||||
"CmdSubmit3d",
|
||||
),
|
||||
(
|
||||
ResourceCreateBlob(virtio_gpu_resource_create_blob::default()),
|
||||
ResourceCreateBlob(virtio_gpu_resource_create_blob::default(), Vec::new()),
|
||||
"ResourceCreateBlob",
|
||||
),
|
||||
(
|
||||
@ -1343,8 +1350,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_virtio_gpu_ctx_create_debug() {
|
||||
let bytes = b"test_debug\0";
|
||||
let original = virtio_gpu_ctx_create {
|
||||
// Test without null terminator (typical case)
|
||||
let bytes = b"test_debug";
|
||||
let ctx = virtio_gpu_ctx_create {
|
||||
debug_name: {
|
||||
let mut debug_name = [0; 64];
|
||||
debug_name[..bytes.len()].copy_from_slice(bytes);
|
||||
@ -1353,12 +1361,26 @@ mod tests {
|
||||
context_init: 0.into(),
|
||||
nlen: (bytes.len() as u32).into(),
|
||||
};
|
||||
|
||||
let debug_string = format!("{original:?}");
|
||||
assert_eq!(
|
||||
debug_string,
|
||||
format!("{ctx:?}"),
|
||||
"virtio_gpu_ctx_create { debug_name: \"test_debug\", context_init: Le32(0), .. }"
|
||||
);
|
||||
|
||||
// Test with null terminator included in nlen (edge case - should preserve it)
|
||||
let bytes_with_null = b"test_debug\0";
|
||||
let ctx_with_null = virtio_gpu_ctx_create {
|
||||
debug_name: {
|
||||
let mut debug_name = [0; 64];
|
||||
debug_name[..bytes_with_null.len()].copy_from_slice(bytes_with_null);
|
||||
debug_name
|
||||
},
|
||||
context_init: 0.into(),
|
||||
nlen: (bytes_with_null.len() as u32).into(),
|
||||
};
|
||||
assert_eq!(
|
||||
format!("{ctx_with_null:?}"),
|
||||
"virtio_gpu_ctx_create { debug_name: \"test_debug\\0\", context_init: Le32(0), .. }"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -8,7 +8,7 @@ use vm_memory::{GuestAddress, GuestMemoryMmap, VolatileSlice};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
use crate::{
|
||||
gpu_types::{ResourceCreate3d, Transfer3DDesc, VirtioGpuRing},
|
||||
gpu_types::{ResourceCreate3d, ResourceCreateBlob, Transfer3DDesc, VirtioGpuRing},
|
||||
protocol::{virtio_gpu_rect, VirtioGpuResult},
|
||||
};
|
||||
|
||||
@ -91,11 +91,9 @@ pub trait Renderer: Send + Sync {
|
||||
fn resource_create_blob(
|
||||
&mut self,
|
||||
ctx_id: u32,
|
||||
resource_id: u32,
|
||||
blob_id: u64,
|
||||
size: u64,
|
||||
blob_mem: u32,
|
||||
blob_flags: u32,
|
||||
resource_create_blob: ResourceCreateBlob,
|
||||
vecs: Vec<(vm_memory::GuestAddress, usize)>,
|
||||
mem: &vm_memory::GuestMemoryMmap,
|
||||
) -> VirtioGpuResult;
|
||||
fn resource_map_blob(&mut self, resource_id: u32, offset: u64) -> VirtioGpuResult;
|
||||
fn resource_unmap_blob(&mut self, resource_id: u32) -> VirtioGpuResult;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user