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:
Gurchetan Singh 2019-04-30 10:22:15 -07:00 committed by Commit Bot
parent 5b636babc1
commit 719f2831ed
4 changed files with 282 additions and 4 deletions

View file

@ -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,
}
}
}

View file

@ -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)
}
}
}

View file

@ -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,

View file

@ -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.