mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 10:10:41 +00:00
virtio-gpu: handle VIRTIO_GPU_CMD_RESOURCE_CREATE_V2
BUG=chromium:924405 TEST=compile Change-Id: I57379452f6805aaf429c268b95ddd3aecd07e90e Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1591463 Reviewed-by: Zach Reizner <zachr@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Tested-by: Gurchetan Singh <gurchetansingh@chromium.org> Commit-Queue: Gurchetan Singh <gurchetansingh@chromium.org>
This commit is contained in:
parent
5b636babc1
commit
719f2831ed
4 changed files with 282 additions and 4 deletions
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -285,6 +285,56 @@ impl Frontend {
|
|||
GpuResponse::ErrUnspec
|
||||
}
|
||||
}
|
||||
GpuCommand::ResourceCreateV2(info) => {
|
||||
if reader.available_bytes() != 0 {
|
||||
let resource_id = info.resource_id.to_native();
|
||||
let guest_memory_type = info.guest_memory_type.to_native();
|
||||
let size = info.size.to_native();
|
||||
let guest_caching_type = info.guest_caching_type.to_native();
|
||||
let pci_addr = info.pci_addr.to_native();
|
||||
let entry_count = info.nr_entries.to_native();
|
||||
let args_size = info.args_size.to_native();
|
||||
if args_size > VIRTIO_GPU_MAX_BLOB_ARGUMENT_SIZE
|
||||
|| entry_count > VIRTIO_GPU_MAX_IOVEC_ENTRIES
|
||||
{
|
||||
return GpuResponse::ErrUnspec;
|
||||
}
|
||||
|
||||
let mut iovecs = Vec::with_capacity(entry_count as usize);
|
||||
let mut args = vec![0; args_size as usize];
|
||||
|
||||
for _ in 0..entry_count {
|
||||
match reader.read_obj::<virtio_gpu_mem_entry>() {
|
||||
Ok(entry) => {
|
||||
let addr = GuestAddress(entry.addr.to_native());
|
||||
let len = entry.length.to_native() as usize;
|
||||
iovecs.push((addr, len))
|
||||
}
|
||||
Err(_) => return GpuResponse::ErrUnspec,
|
||||
}
|
||||
}
|
||||
|
||||
match reader.read(&mut args[..]) {
|
||||
Ok(_) => self.backend.resource_create_v2(
|
||||
resource_id,
|
||||
guest_memory_type,
|
||||
guest_caching_type,
|
||||
size,
|
||||
pci_addr,
|
||||
mem,
|
||||
iovecs,
|
||||
args,
|
||||
),
|
||||
Err(_) => GpuResponse::ErrUnspec,
|
||||
}
|
||||
} else {
|
||||
GpuResponse::ErrUnspec
|
||||
}
|
||||
}
|
||||
GpuCommand::ResourceV2Unref(info) => {
|
||||
let resource_id = info.resource_id.to_native();
|
||||
self.backend.resource_v2_unref(resource_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,6 +86,8 @@ pub const VIRTIO_GPU_UNCACHED: u32 = 3;
|
|||
|
||||
/* Limits on virtio-gpu stream (not upstreamed) */
|
||||
pub const VIRTIO_GPU_MAX_BLOB_ARGUMENT_SIZE: u32 = 4096;
|
||||
/* This matches the limit in udmabuf.c */
|
||||
pub const VIRTIO_GPU_MAX_IOVEC_ENTRIES: u32 = 1024;
|
||||
|
||||
pub fn virtio_gpu_cmd_str(cmd: u32) -> &'static str {
|
||||
match cmd {
|
||||
|
@ -515,6 +517,32 @@ pub struct virtio_gpu_resp_allocation_metadata {
|
|||
|
||||
unsafe impl DataInit for virtio_gpu_resp_allocation_metadata {}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct virtio_gpu_resource_create_v2 {
|
||||
pub hdr: virtio_gpu_ctrl_hdr,
|
||||
pub resource_id: Le32,
|
||||
pub guest_memory_type: Le32,
|
||||
pub guest_caching_type: Le32,
|
||||
pub padding: Le32,
|
||||
pub size: Le64,
|
||||
pub pci_addr: Le64,
|
||||
pub args_size: Le32,
|
||||
pub nr_entries: Le32,
|
||||
}
|
||||
|
||||
unsafe impl DataInit for virtio_gpu_resource_create_v2 {}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct virtio_gpu_resource_v2_unref {
|
||||
pub hdr: virtio_gpu_ctrl_hdr,
|
||||
pub resource_id: Le32,
|
||||
pub padding: Le32,
|
||||
}
|
||||
|
||||
unsafe impl DataInit for virtio_gpu_resource_v2_unref {}
|
||||
|
||||
/* simple formats for fbcon/X use */
|
||||
pub const VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: u32 = 1;
|
||||
pub const VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: u32 = 2;
|
||||
|
@ -546,6 +574,8 @@ pub enum GpuCommand {
|
|||
TransferToHost3d(virtio_gpu_transfer_host_3d),
|
||||
TransferFromHost3d(virtio_gpu_transfer_host_3d),
|
||||
CmdSubmit3d(virtio_gpu_cmd_submit),
|
||||
ResourceCreateV2(virtio_gpu_resource_create_v2),
|
||||
ResourceV2Unref(virtio_gpu_resource_v2_unref),
|
||||
AllocationMetadata(virtio_gpu_allocation_metadata),
|
||||
UpdateCursor(virtio_gpu_update_cursor),
|
||||
MoveCursor(virtio_gpu_update_cursor),
|
||||
|
@ -604,6 +634,8 @@ impl fmt::Debug for GpuCommand {
|
|||
TransferToHost3d(_info) => f.debug_struct("TransferToHost3d").finish(),
|
||||
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(),
|
||||
AllocationMetadata(_info) => f.debug_struct("AllocationMetadata").finish(),
|
||||
UpdateCursor(_info) => f.debug_struct("UpdateCursor").finish(),
|
||||
MoveCursor(_info) => f.debug_struct("MoveCursor").finish(),
|
||||
|
@ -635,6 +667,8 @@ impl GpuCommand {
|
|||
VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D => TransferToHost3d(cmd.read_obj()?),
|
||||
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_ALLOCATION_METADATA => AllocationMetadata(cmd.read_obj()?),
|
||||
VIRTIO_GPU_CMD_UPDATE_CURSOR => UpdateCursor(cmd.read_obj()?),
|
||||
VIRTIO_GPU_CMD_MOVE_CURSOR => MoveCursor(cmd.read_obj()?),
|
||||
|
@ -664,6 +698,8 @@ impl GpuCommand {
|
|||
TransferToHost3d(info) => &info.hdr,
|
||||
TransferFromHost3d(info) => &info.hdr,
|
||||
CmdSubmit3d(info) => &info.hdr,
|
||||
ResourceCreateV2(info) => &info.hdr,
|
||||
ResourceV2Unref(info) => &info.hdr,
|
||||
AllocationMetadata(info) => &info.hdr,
|
||||
UpdateCursor(info) => &info.hdr,
|
||||
MoveCursor(info) => &info.hdr,
|
||||
|
|
|
@ -410,6 +410,62 @@ impl Renderer {
|
|||
#[cfg(not(feature = "virtio-gpu-next"))]
|
||||
Err(Error::Unsupported)
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub fn resource_create_v2(
|
||||
&self,
|
||||
resource_id: u32,
|
||||
guest_memory_type: u32,
|
||||
guest_caching_type: u32,
|
||||
size: u64,
|
||||
mem: &GuestMemory,
|
||||
iovecs: &[(GuestAddress, usize)],
|
||||
args: &[u8],
|
||||
) -> Result<Resource> {
|
||||
#[cfg(feature = "virtio-gpu-next")]
|
||||
{
|
||||
if iovecs
|
||||
.iter()
|
||||
.any(|&(addr, len)| mem.get_slice(addr.offset(), len as u64).is_err())
|
||||
{
|
||||
return Err(Error::InvalidIovec);
|
||||
}
|
||||
|
||||
let mut vecs = Vec::new();
|
||||
for &(addr, len) in iovecs {
|
||||
// Unwrap will not panic because we already checked the slices.
|
||||
let slice = mem.get_slice(addr.offset(), len as u64).unwrap();
|
||||
vecs.push(VirglVec {
|
||||
base: slice.as_ptr() as *mut c_void,
|
||||
len,
|
||||
});
|
||||
}
|
||||
|
||||
let ret = unsafe {
|
||||
virgl_renderer_resource_create_v2(
|
||||
resource_id,
|
||||
guest_memory_type,
|
||||
guest_caching_type,
|
||||
size,
|
||||
vecs.as_ptr() as *const iovec,
|
||||
vecs.len() as u32,
|
||||
args.as_ptr() as *const c_void,
|
||||
args.len() as u32,
|
||||
)
|
||||
};
|
||||
|
||||
ret_to_res(ret)?;
|
||||
|
||||
Ok(Resource {
|
||||
id: resource_id,
|
||||
backing_iovecs: vecs,
|
||||
backing_mem: None,
|
||||
no_sync_send: PhantomData,
|
||||
})
|
||||
}
|
||||
#[cfg(not(feature = "virtio-gpu-next"))]
|
||||
Err(Error::Unsupported)
|
||||
}
|
||||
}
|
||||
|
||||
/// A context in which resources can be attached/detached and commands can be submitted.
|
||||
|
|
Loading…
Reference in a new issue